libMesh
cell_inf_prism.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2019 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 
32 namespace libMesh
33 {
34 
35 
36 // ------------------------------------------------------------
37 // InfPrism class static member initializations
38 
39 
40 // We need to require C++11...
41 const Real InfPrism::_master_points[12][3] =
42  {
43  {0, 0, 0},
44  {1, 0, 0},
45  {0, 1, 0},
46  {0, 0, 1},
47  {1, 0, 1},
48  {0, 1, 1},
49  {.5, 0, 0},
50  {.5, .5, 0},
51  {0, .5, 0},
52  {.5, 0, 1},
53  {.5, .5, 1},
54  {0, .5, 1}
55  };
56 
57 
58 
59 // ------------------------------------------------------------
60 // InfPrism class member functions
61 dof_id_type InfPrism::key (const unsigned int s) const
62 {
63  libmesh_assert_less (s, this->n_sides());
64 
65  switch (s)
66  {
67  case 0: // the triangular face at z=-1, base face
68  return this->compute_key (this->node_id(InfPrism6::side_nodes_map[s][0]),
70  this->node_id(InfPrism6::side_nodes_map[s][2]));
71 
72  case 1: // the quad face at y=0
73  case 2: // the other quad face
74  case 3: // the quad face at x=0
75  return this->compute_key (this->node_id(InfPrism6::side_nodes_map[s][0]),
78  this->node_id(InfPrism6::side_nodes_map[s][3]));
79 
80  default:
81  libmesh_error_msg("Invalid side s = " << s);
82  }
83 }
84 
85 
86 
87 unsigned int InfPrism::which_node_am_i(unsigned int side,
88  unsigned int side_node) const
89 {
90  libmesh_assert_less (side, this->n_sides());
91 
92  // Never more than 4 nodes per side.
93  libmesh_assert_less(side_node, 4);
94 
95  // Some sides have 3 nodes.
96  libmesh_assert(side != 0 || side_node < 3);
97 
98  return InfPrism6::side_nodes_map[side][side_node];
99 }
100 
101 
102 
103 std::unique_ptr<Elem> InfPrism::side_ptr (const unsigned int i)
104 {
105  libmesh_assert_less (i, this->n_sides());
106 
107  std::unique_ptr<Elem> face;
108 
109  switch (i)
110  {
111  case 0: // the triangular face at z=-1, base face
112  {
113  face = libmesh_make_unique<Tri3>();
114  break;
115  }
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  {
121  face = libmesh_make_unique<InfQuad4>();
122  break;
123  }
124 
125  default:
126  libmesh_error_msg("Invalid side i = " << i);
127  }
128 
129  // Set the nodes
130  for (auto n : face->node_index_range())
131  face->set_node(n) = this->node_ptr(InfPrism6::side_nodes_map[i][n]);
132 
133  return face;
134 }
135 
136 
137 
138 void InfPrism::side_ptr (std::unique_ptr<Elem> & side,
139  const unsigned int i)
140 {
141  libmesh_assert_less (i, this->n_sides());
142 
143  switch (i)
144  {
145  // the base face
146  case 0:
147  {
148  if (!side.get() || side->type() != TRI3)
149  {
150  side = this->side_ptr(i);
151  return;
152  }
153  break;
154  }
155 
156  // connecting to another infinite element
157  case 1:
158  case 2:
159  case 3:
160  case 4:
161  {
162  if (!side.get() || side->type() != INFQUAD4)
163  {
164  side = this->side_ptr(i);
165  return;
166  }
167  break;
168  }
169 
170  default:
171  libmesh_error_msg("Invalid side i = " << i);
172  }
173 
174  side->subdomain_id() = this->subdomain_id();
175 
176  // Set the nodes
177  for (auto n : side->node_index_range())
178  side->set_node(n) = this->node_ptr(InfPrism6::side_nodes_map[i][n]);
179 }
180 
181 
182 
183 bool InfPrism::is_child_on_side(const unsigned int c,
184  const unsigned int s) const
185 {
186  libmesh_assert_less (c, this->n_children());
187  libmesh_assert_less (s, this->n_sides());
188 
189  return (s == 0 || c+1 == s || c == s%3);
190 }
191 
192 
193 
194 bool InfPrism::is_edge_on_side (const unsigned int e,
195  const unsigned int s) const
196 {
197  libmesh_assert_less (e, this->n_edges());
198  libmesh_assert_less (s, this->n_sides());
199 
200  return (is_node_on_side(InfPrism6::edge_nodes_map[e][0],s) &&
202 }
203 
204 bool InfPrism::contains_point (const Point & p, Real tol) const
205 {
206  // For infinite elements with linear base interpolation:
207  // make use of the fact that infinite elements do not
208  // live inside the envelope. Use a fast scheme to
209  // check whether point \p p is inside or outside
210  // our relevant part of the envelope. Note that
211  // this is not exclusive: only when the distance is less,
212  // we are safe. Otherwise, we cannot say anything. The
213  // envelope may be non-spherical, the physical point may lie
214  // inside the envelope, outside the envelope, or even inside
215  // this infinite element. Therefore if this fails,
216  // fall back to the inverse_map()
217  const Point my_origin (this->origin());
218 
219  // determine the minimal distance of the base from the origin
220  // use norm_sq(), it is faster than norm() and produces
221  // the same behavior. Shift my_origin to center first:
222  Point pt0_o(this->point(0) - my_origin);
223  Point pt1_o(this->point(1) - my_origin);
224  Point pt2_o(this->point(2) - my_origin);
225  const Real tmp_min_distance_sq = std::min(pt0_o.norm_sq(),
226  std::min(pt1_o.norm_sq(),
227  pt2_o.norm_sq()));
228 
229  // For a coarse grid, it is important to account for the fact
230  // that the sides are not spherical, thus the closest point
231  // can be closer than all edges.
232  // This is an estimator using Pythagoras:
233  const Real min_distance_sq = tmp_min_distance_sq
234  - .5*std::max((point(0)-point(1)).norm_sq(),
235  std::max((point(0)-point(2)).norm_sq(),
236  (point(1)-point(2)).norm_sq()));
237 
238  // work with 1% allowable deviation. We can still fall
239  // back to the InfFE::inverse_map()
240  const Real conservative_p_dist_sq = 1.01 * (Point(p - my_origin).norm_sq());
241 
242  if (conservative_p_dist_sq < min_distance_sq)
243  {
244  // the physical point is definitely not contained in the element:
245  return false;
246  }
247 
248  // this captures the case that the point is not (almost) in the direction of the element.:
249  // first, project the problem onto the unit sphere:
250  Point p_o(p - my_origin);
251  pt0_o /= pt0_o.norm();
252  pt1_o /= pt1_o.norm();
253  pt2_o /= pt2_o.norm();
254  p_o /= p_o.norm();
255 
256  // now, check if it is in the projected face; by comparing the distance of
257  // any point in the element to \p p with the largest distance between this point
258  // to any other point in the element.
259  if ((p_o - pt0_o).norm_sq() > std::max((pt0_o - pt1_o).norm_sq(), (pt0_o - pt2_o).norm_sq()) ||
260  (p_o - pt1_o).norm_sq() > std::max((pt1_o - pt2_o).norm_sq(), (pt1_o - pt0_o).norm_sq()) ||
261  (p_o - pt2_o).norm_sq() > std::max((pt2_o - pt0_o).norm_sq(), (pt2_o - pt1_o).norm_sq()) )
262  {
263  // the physical point is definitely not contained in the element
264  return false;
265  }
266 
267 
268  // It seems that \p p is at least close to this element.
269  //
270  // Declare a basic FEType. Will use default in the base,
271  // and something else (not important) in radial direction.
272  FEType fe_type(default_order());
273 
274  const Point mapped_point = InfFEMap::inverse_map(dim(), this, p,
275  tol, false);
276 
277  return FEInterface::on_reference_element(mapped_point, this->type(), tol);
278 }
279 
280 
281 } // namespace libMesh
282 
283 
284 
285 #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
libMesh::dof_id_type
uint8_t dof_id_type
Definition: id_types.h:67
libMesh::Elem::is_node_on_side
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
libMesh::Elem::compute_key
static dof_id_type compute_key(dof_id_type n0)
Definition: elem.h:2683
libMesh::FEInterface::on_reference_element
static bool on_reference_element(const Point &p, const ElemType t, const Real eps=TOLERANCE)
Definition: fe_interface.C:677
libMesh::InfPrism6::edge_nodes_map
static const unsigned int edge_nodes_map[num_edges][nodes_per_edge]
This maps the node of the edge to element node numbers.
Definition: cell_inf_prism6.h:174
libMesh::INFQUAD4
Definition: enum_elem_type.h:58
libMesh::InfPrism::n_sides
virtual unsigned int n_sides() const override final
Definition: cell_inf_prism.h:81
libMesh::InfCell::dim
virtual unsigned short dim() const override
Definition: cell_inf.h:66
libMesh
The libMesh namespace provides an interface to certain functionality in the library.
Definition: factoryfunction.C:55
libMesh::InfPrism::is_edge_on_side
virtual bool is_edge_on_side(const unsigned int e, const unsigned int s) const override final
Definition: cell_inf_prism.C:194
libMesh::Elem::point
const Point & point(const unsigned int i) const
Definition: elem.h:1955
libMesh::libmesh_assert
libmesh_assert(ctx)
libMesh::InfPrism::_master_points
static const Real _master_points[12][3]
Master element node locations.
Definition: cell_inf_prism.h:172
libMesh::InfFEMap::inverse_map
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:88
libMesh::TypeVector::norm_sq
auto norm_sq() const -> decltype(std::norm(T()))
Definition: type_vector.h:986
libMesh::InfCell::origin
virtual Point origin() const override
Definition: cell_inf.h:77
libMesh::Point
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:38
libMesh::InfPrism6::side_nodes_map
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
This maps the node of the side to element node numbers.
Definition: cell_inf_prism6.h:168
libMesh::Elem::key
virtual dof_id_type key() const
Definition: elem.C:410
libMesh::TRI3
Definition: enum_elem_type.h:39
libMesh::Elem::default_order
virtual Order default_order() const =0
libMesh::InfPrism::which_node_am_i
virtual unsigned int which_node_am_i(unsigned int side, unsigned int side_node) const override
Definition: cell_inf_prism.C:87
libMesh::InfPrism::n_edges
virtual unsigned int n_edges() const override final
Definition: cell_inf_prism.h:93
libMesh::TensorTools::norm_sq
T norm_sq(std::complex< T > a)
Definition: tensor_tools.h:85
libMesh::FEType
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:178
libMesh::InfPrism::side_ptr
virtual std::unique_ptr< Elem > side_ptr(const unsigned int i) override final
Definition: cell_inf_prism.C:103
libMesh::Elem::subdomain_id
subdomain_id_type subdomain_id() const
Definition: elem.h:2069
libMesh::InfPrism::n_children
virtual unsigned int n_children() const override final
Definition: cell_inf_prism.h:103
libMesh::Elem::node_id
dof_id_type node_id(const unsigned int i) const
Definition: elem.h:1977
libMesh::InfPrism::contains_point
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const override
Definition: cell_inf_prism.C:204
libMesh::Real
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Definition: libmesh_common.h:121
libMesh::TypeVector::norm
auto norm() const -> decltype(std::norm(T()))
Definition: type_vector.h:955
libMesh::Elem::node_ptr
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:2009
libMesh::Elem::type
virtual ElemType type() const =0
libMesh::InfPrism::is_child_on_side
virtual bool is_child_on_side(const unsigned int c, const unsigned int s) const override final
Definition: cell_inf_prism.C:183