libMesh
Loading...
Searching...
No Matches
cell_inf_prism.C
Go to the documentation of this file.
1// The libMesh Finite Element Library.
2// Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3
4// This library is free software; you can redistribute it and/or
5// modify it under the terms of the GNU Lesser General Public
6// License as published by the Free Software Foundation; either
7// version 2.1 of the License, or (at your option) any later version.
8
9// This library is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12// Lesser General Public License for more details.
13
14// You should have received a copy of the GNU Lesser General Public
15// License along with this library; if not, write to the Free Software
16// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17
18#include "libmesh/libmesh_config.h"
19
20#ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
21
22// Local includes
23#include "libmesh/cell_inf_prism.h"
24#include "libmesh/cell_inf_prism6.h"
25#include "libmesh/face_tri3.h"
26#include "libmesh/face_inf_quad4.h"
27#include "libmesh/fe_type.h"
28#include "libmesh/fe_interface.h"
29#include "libmesh/inf_fe_map.h"
30#include "libmesh/enum_order.h"
31
32namespace libMesh
33{
34
35
36// ------------------------------------------------------------
37// InfPrism class static member initializations
38const int InfPrism::num_sides;
39const int InfPrism::num_edges;
41
42const Real InfPrism::_master_points[12][3] =
43 {
44 {0, 0, 0},
45 {1, 0, 0},
46 {0, 1, 0},
47 {0, 0, 1},
48 {1, 0, 1},
49 {0, 1, 1},
50 {.5, 0, 0},
51 {.5, .5, 0},
52 {0, .5, 0},
53 {.5, 0, 1},
54 {.5, .5, 1},
55 {0, .5, 1}
56 };
57
58const unsigned int InfPrism::edge_sides_map[6][2] =
59 {
60 {0, 1}, // Edge 0
61 {0, 2}, // Edge 1
62 {0, 3}, // Edge 2
63 {1, 3}, // Edge 3
64 {1, 2}, // Edge 4
65 {2, 3} // Edge 5
66 };
67
68const unsigned int InfPrism::adjacent_edges_map[/*num_vertices*/6][/*max_adjacent_edges*/3] =
69{
70 {0, 2, 3}, // Edges adjacent to node 0
71 {0, 1, 4}, // Edges adjacent to node 1
72 {1, 2, 5}, // Edges adjacent to node 2
73 {3, 99, 99}, // Edges adjacent to node 3
74 {4, 99, 99}, // Edges adjacent to node 4
75 {5, 99, 99}, // Edges adjacent to node 5
76};
77
78// ------------------------------------------------------------
79// InfPrism class member functions
80dof_id_type InfPrism::key (const unsigned int s) const
81{
82 libmesh_assert_less (s, this->n_sides());
83
84 switch (s)
85 {
86 case 0: // the triangular face at z=-1, base face
87 return this->compute_key (this->node_id(InfPrism6::side_nodes_map[s][0]),
90
91 case 1: // the quad face at y=0
92 case 2: // the other quad face
93 case 3: // the quad face at x=0
94 return this->compute_key (this->node_id(InfPrism6::side_nodes_map[s][0]),
98
99 default:
100 libmesh_error_msg("Invalid side s = " << s);
101 }
102}
103
104
105
106dof_id_type InfPrism::low_order_key (const unsigned int s) const
107{
108 libmesh_assert_less (s, this->n_sides());
109
110 switch (s)
111 {
112 case 0: // the triangular face at z=-1, base face
113 return this->compute_key (this->node_id(InfPrism6::side_nodes_map[s][0]),
116
117 case 1: // the quad face at y=0
118 case 2: // the other quad face
119 case 3: // the quad face at x=0
120 return this->compute_key (this->node_id(InfPrism6::side_nodes_map[s][0]),
124
125 default:
126 libmesh_error_msg("Invalid side s = " << s);
127 }
128}
129
130
131
132unsigned int InfPrism::local_side_node(unsigned int side,
133 unsigned int side_node) const
134{
135 libmesh_assert_less (side, this->n_sides());
136
137 // Never more than 4 nodes per side.
138 libmesh_assert_less(side_node, InfPrism6::nodes_per_side);
139
140 // Some sides have 3 nodes.
141 libmesh_assert(side != 0 || side_node < 3);
142
143 return InfPrism6::side_nodes_map[side][side_node];
144}
145
146
147
148unsigned int InfPrism::local_edge_node(unsigned int edge,
149 unsigned int edge_node) const
150{
151 libmesh_assert_less(edge, this->n_edges());
152 libmesh_assert_less(edge_node, InfPrism6::nodes_per_edge);
153
154 return InfPrism6::edge_nodes_map[edge][edge_node];
155}
156
157
158
159std::unique_ptr<Elem> InfPrism::side_ptr (const unsigned int i)
160{
161 libmesh_assert_less (i, this->n_sides());
162
163 std::unique_ptr<Elem> face;
164
165 switch (i)
166 {
167 case 0: // the triangular face at z=-1, base face
168 {
169 face = std::make_unique<Tri3>();
170 break;
171 }
172
173 case 1: // the quad face at y=0
174 case 2: // the other quad face
175 case 3: // the quad face at x=0
176 {
177 face = std::make_unique<InfQuad4>();
178 break;
179 }
180
181 default:
182 libmesh_error_msg("Invalid side i = " << i);
183 }
184
185 // Set the nodes
186 for (auto n : face->node_index_range())
187 face->set_node(n, this->node_ptr(InfPrism6::side_nodes_map[i][n]));
188
189 return face;
190}
191
192
193
194void InfPrism::side_ptr (std::unique_ptr<Elem> & side,
195 const unsigned int i)
196{
197 libmesh_assert_less (i, this->n_sides());
198
199 switch (i)
200 {
201 // the base face
202 case 0:
203 {
204 if (!side.get() || side->type() != TRI3)
205 {
206 side = this->side_ptr(i);
207 return;
208 }
209 break;
210 }
211
212 // connecting to another infinite element
213 case 1:
214 case 2:
215 case 3:
216 case 4:
217 {
218 if (!side.get() || side->type() != INFQUAD4)
219 {
220 side = this->side_ptr(i);
221 return;
222 }
223 break;
224 }
225
226 default:
227 libmesh_error_msg("Invalid side i = " << i);
228 }
229
230 side->subdomain_id() = this->subdomain_id();
231
232 // Set the nodes
233 for (auto n : side->node_index_range())
234 side->set_node(n, this->node_ptr(InfPrism6::side_nodes_map[i][n]));
235}
236
237
238
239bool InfPrism::is_child_on_side(const unsigned int c,
240 const unsigned int s) const
241{
242 libmesh_assert_less (c, this->n_children());
243 libmesh_assert_less (s, this->n_sides());
244
245 return (s == 0 || c+1 == s || c == s%3);
246}
247
248
249
250bool InfPrism::is_edge_on_side (const unsigned int e,
251 const unsigned int s) const
252{
253 libmesh_assert_less (e, this->n_edges());
254 libmesh_assert_less (s, this->n_sides());
255
256 return (edge_sides_map[e][0] == s || edge_sides_map[e][1] == s);
257}
258
259bool InfPrism::contains_point (const Point & p, Real tol) const
260{
261 // For infinite elements with linear base interpolation:
262 // make use of the fact that infinite elements do not
263 // live inside the envelope. Use a fast scheme to
264 // check whether point \p p is inside or outside
265 // our relevant part of the envelope. Note that
266 // this is not exclusive: only when the distance is less,
267 // we are safe. Otherwise, we cannot say anything. The
268 // envelope may be non-spherical, the physical point may lie
269 // inside the envelope, outside the envelope, or even inside
270 // this infinite element. Therefore if this fails,
271 // fall back to the inverse_map()
272 const Point my_origin (this->origin());
273
274 // determine the minimal distance of the base from the origin
275 // use norm_sq(), it is faster than norm() and produces
276 // the same behavior. Shift my_origin to center first:
277 Point pt0_o(this->point(0) - my_origin);
278 Point pt1_o(this->point(1) - my_origin);
279 Point pt2_o(this->point(2) - my_origin);
280 const Real tmp_min_distance_sq = std::min(pt0_o.norm_sq(),
281 std::min(pt1_o.norm_sq(),
282 pt2_o.norm_sq()));
283
284 // For a coarse grid, it is important to account for the fact
285 // that the sides are not spherical, thus the closest point
286 // can be closer than all edges.
287 // This is an estimator using Pythagoras:
288 const Real min_distance_sq = tmp_min_distance_sq
289 - .5*std::max((point(0)-point(1)).norm_sq(),
290 std::max((point(0)-point(2)).norm_sq(),
291 (point(1)-point(2)).norm_sq()));
292
293 // work with 1% allowable deviation. We can still fall
294 // back to the InfFE::inverse_map()
295 const Real conservative_p_dist_sq = 1.01 * (Point(p - my_origin).norm_sq());
296
297 if (conservative_p_dist_sq < min_distance_sq)
298 {
299 // the physical point is definitely not contained in the element:
300 return false;
301 }
302
303 // this captures the case that the point is not (almost) in the direction of the element.:
304 // first, project the problem onto the unit sphere:
305 Point p_o(p - my_origin);
306 pt0_o /= pt0_o.norm();
307 pt1_o /= pt1_o.norm();
308 pt2_o /= pt2_o.norm();
309 p_o /= p_o.norm();
310
311 // now, check if it is in the projected face; by comparing the distance of
312 // any point in the element to \p p with the largest distance between this point
313 // to any other point in the element.
314 if ((p_o - pt0_o).norm_sq() > std::max((pt0_o - pt1_o).norm_sq(), (pt0_o - pt2_o).norm_sq()) ||
315 (p_o - pt1_o).norm_sq() > std::max((pt1_o - pt2_o).norm_sq(), (pt1_o - pt0_o).norm_sq()) ||
316 (p_o - pt2_o).norm_sq() > std::max((pt2_o - pt0_o).norm_sq(), (pt2_o - pt1_o).norm_sq()) )
317 {
318 // the physical point is definitely not contained in the element
319 return false;
320 }
321
322
323 // It seems that \p p is at least close to this element.
324 //
325 // Declare a basic FEType. Will use default in the base,
326 // and something else (not important) in radial direction.
327 FEType fe_type(default_order());
328
329 const Point mapped_point = InfFEMap::inverse_map(dim(), this, p,
330 tol, false);
331
332 return this->on_reference_element(mapped_point, tol);
333}
334
335std::vector<unsigned>
336InfPrism::sides_on_edge(const unsigned int e) const
337{
338 libmesh_assert_less(e, n_edges());
339 return {std::begin(edge_sides_map[e]), std::end(edge_sides_map[e])};
340}
341
342
343bool
345{
346 return (triple_product(this->point(1)-this->point(0),
347 this->point(2)-this->point(0),
348 this->point(3)-this->point(0)) < 0);
349}
350
351std::vector<unsigned int>
352InfPrism::edges_adjacent_to_node(const unsigned int n) const
353{
354 libmesh_assert_less(n, this->n_nodes());
355
356 // For vertices, we use the InfPrism::adjacent_edges_map with
357 // appropriate "trimming" based on whether the vertices are "at
358 // infinity" or not. Otherwise each of the mid-edge nodes is
359 // adjacent only to the edge it is on, and the remaining nodes are
360 // not adjacent to any edge.
361 if (this->is_vertex(n))
362 {
363 auto trim = (n < 3) ? 0 : 2;
364 return {std::begin(adjacent_edges_map[n]), std::end(adjacent_edges_map[n]) - trim};
365 }
366 else if (this->is_edge(n))
367 return {n - this->n_vertices()};
368
369 libmesh_assert(this->is_face(n) || this->is_internal(n));
370 return {};
371}
372
373
374
376 const Real eps) const
377{
378 const Real & xi = p(0);
379 const Real & eta = p(1);
380 const Real & zeta = p(2);
381
382 // inside the reference triangle with zeta in [-1,1]
383 return ((xi >= 0.-eps) &&
384 (eta >= 0.-eps) &&
385 (zeta >= -1.-eps) &&
386 (zeta <= 1.+eps) &&
387 ((xi + eta) <= 1.+eps));
388}
389
390
391
392
393} // namespace libMesh
394
395
396
397#endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
const Point & point(const unsigned int i) const
Definition elem.h:2462
virtual unsigned int n_nodes() const =0
virtual Order default_order() const =0
subdomain_id_type subdomain_id() const
Definition elem.h:2591
static dof_id_type compute_key(dof_id_type n0)
Definition elem.h:3311
bool is_internal(const unsigned int i) const
Definition elem.C:3611
dof_id_type node_id(const unsigned int i) const
Definition elem.h:2484
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
virtual Point origin() const override
Definition cell_inf.h:77
virtual unsigned short dim() const override
Definition cell_inf.h:66
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition inf_fe_map.C:96
static const int nodes_per_edge
static const int nodes_per_side
static const unsigned int edge_nodes_map[num_edges][nodes_per_edge]
This maps the node of the edge to element node numbers.
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
This maps the node of the side to element node numbers.
std::vector< unsigned int > sides_on_edge(const unsigned int e) const override final
virtual unsigned int n_vertices() const override final
static const Real _master_points[12][3]
Master element node locations.
virtual std::unique_ptr< Elem > side_ptr(const unsigned int i) override final
static const int num_edges
virtual unsigned int n_edges() const override final
static const int num_sides
Geometric constants for all InfPrisms.
virtual unsigned int local_edge_node(unsigned int edge, unsigned int edge_node) const override
virtual std::vector< unsigned int > edges_adjacent_to_node(const unsigned int n) const override
virtual bool is_flipped() const override final
virtual bool on_reference_element(const Point &p, const Real eps=TOLERANCE) const override final
virtual bool is_vertex(const unsigned int i) const override final
We number vertices first.
virtual bool is_edge_on_side(const unsigned int e, const unsigned int s) const override final
static const unsigned int adjacent_edges_map[6][3]
This maps the node to the 3 (or fewer) edge ids adjacent to the node.
virtual dof_id_type key() const
Don't hide Elem::key() defined in the base class.
Definition elem.C:738
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const override final
virtual unsigned int n_sides() const override final
virtual unsigned int local_side_node(unsigned int side, unsigned int side_node) const override
virtual dof_id_type low_order_key(const unsigned int s) const override
static const unsigned int edge_sides_map[6][2]
This maps each edge to the sides that contain said edge.
virtual unsigned int n_children() const override final
virtual bool is_edge(const unsigned int i) const override final
We number edges next.
static const int num_children
virtual bool is_face(const unsigned int i) const override final
We number faces last.
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const override
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
auto norm_sq() const
auto norm() const
The libMesh namespace provides an interface to certain functionality in the library.
T triple_product(const TypeVector< T > &a, const TypeVector< T > &b, const TypeVector< T > &c)
libmesh_assert(ctx)
uint8_t dof_id_type
Definition id_types.h:67
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real