face_inf_quad4.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2018 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 
19 
20 #include "libmesh/libmesh_config.h"
21 
22 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
23 
24 // Local includes
25 #include "libmesh/face_inf_quad4.h"
26 #include "libmesh/fe_interface.h"
27 #include "libmesh/fe_type.h"
28 #include "libmesh/side.h"
29 #include "libmesh/edge_edge2.h"
30 #include "libmesh/edge_inf_edge2.h"
32 #include "libmesh/enum_order.h"
33 
34 namespace libMesh
35 {
36 
37 
38 
39 // ------------------------------------------------------------
40 // InfQuad4 class static member initializations
41 const int InfQuad4::num_nodes;
42 const int InfQuad4::num_sides;
43 const int InfQuad4::num_children;
44 const int InfQuad4::nodes_per_side;
45 
47  {
48  {0, 1}, // Side 0
49  {1, 3}, // Side 1
50  {0, 2} // Side 2
51  };
52 
53 
54 
55 #ifdef LIBMESH_ENABLE_AMR
56 
58  {
59  // embedding matrix for child 0
60  {
61  // 0 1 2 3rd parent node
62  {1.0, 0.0, 0.0, 0.0}, // 0th child node
63  {0.5, 0.5, 0.0, 0.0}, // 1
64  {0.0, 0.0, 1.0, 0.0}, // 2
65  {0.0, 0.0, 0.5, 0.5} // 3
66  },
67 
68  // embedding matrix for child 1
69  {
70  // 0 1 2 3
71  {0.5, 0.5, 0.0, 0.0}, // 0
72  {0.0, 1.0, 0.0, 0.0}, // 1
73  {0.0, 0.0, 0.5, 0.5}, // 2
74  {0.0, 0.0, 0.0, 1.0} // 3
75  }
76  };
77 
78 #endif
79 
80 
81 // ------------------------------------------------------------
82 // InfQuad4 class member functions
83 
84 bool InfQuad4::is_vertex(const unsigned int i) const
85 {
86  if (i < 2)
87  return true;
88  return false;
89 }
90 
91 bool InfQuad4::is_edge(const unsigned int i) const
92 {
93  if (i < 2)
94  return false;
95  return true;
96 }
97 
98 bool InfQuad4::is_face(const unsigned int) const
99 {
100  return false;
101 }
102 
103 bool InfQuad4::is_node_on_side(const unsigned int n,
104  const unsigned int s) const
105 {
106  libmesh_assert_less (s, n_sides());
107  return std::find(std::begin(side_nodes_map[s]),
109  n) != std::end(side_nodes_map[s]);
110 }
111 
112 std::vector<unsigned>
113 InfQuad4::nodes_on_side(const unsigned int s) const
114 {
115  libmesh_assert_less(s, n_sides());
116  return {std::begin(side_nodes_map[s]), std::end(side_nodes_map[s])};
117 }
118 
119 bool InfQuad4::contains_point (const Point & p, Real tol) const
120 {
121  /*
122  * make use of the fact that infinite elements do not
123  * live inside the envelope. Use a fast scheme to
124  * check whether point \p p is inside or outside
125  * our relevant part of the envelope. Note that
126  * this is not exclusive: the point may be outside
127  * the envelope, but contained in another infinite element.
128  * Therefore, if the distance is greater, do fall back
129  * to the scheme of using FEInterface::inverse_map().
130  */
131  const Point my_origin (this->origin());
132 
133  /*
134  * determine the minimal distance of the base from the origin
135  * use norm_sq() instead of norm(), it is slightly faster
136  */
137  const Real min_distance_sq = std::min((Point(this->point(0)-my_origin)).norm_sq(),
138  (Point(this->point(1)-my_origin)).norm_sq());
139 
140  /*
141  * work with 1% allowable deviation. Can still fall
142  * back to the InfFE::inverse_map()
143  */
144  const Real conservative_p_dist_sq = 1.01 * (Point(p-my_origin).norm_sq());
145 
146  if (conservative_p_dist_sq < min_distance_sq)
147  {
148  /*
149  * the physical point is definitely not contained
150  * in the element, return false.
151  */
152  return false;
153  }
154  else
155  {
156  /*
157  * cannot say anything, fall back to the FEInterface::inverse_map()
158  *
159  * Declare a basic FEType. Will use default in the base,
160  * and something else (not important) in radial direction.
161  */
162  FEType fe_type(default_order());
163 
164  const Point mapped_point = FEInterface::inverse_map(dim(),
165  fe_type,
166  this,
167  p,
168  tol,
169  false);
170 
171  return FEInterface::on_reference_element(mapped_point, this->type(), tol);
172  }
173 }
174 
175 
176 
177 
179 {
180  return FIRST;
181 }
182 
183 
184 
185 std::unique_ptr<Elem> InfQuad4::build_side_ptr (const unsigned int i,
186  bool proxy)
187 {
188  // libmesh_assert_less (i, this->n_sides());
189 
190  if (proxy)
191  {
192  switch (i)
193  {
194  // base
195  case 0:
196  return libmesh_make_unique<Side<Edge2,InfQuad4>>(this,i);
197 
198  // ifem edges
199  case 1:
200  case 2:
201  return libmesh_make_unique<Side<InfEdge2,InfQuad4>>(this,i);
202 
203  default:
204  libmesh_error_msg("Invalid side i = " << i);
205  }
206  }
207 
208  else
209  {
210  // Return value
211  std::unique_ptr<Elem> edge;
212 
213  switch (i)
214  {
215  case 0:
216  {
217  edge = libmesh_make_unique<Edge2>();
218  break;
219  }
220 
221  // adjacent to another infinite element
222  case 1:
223  case 2:
224  {
225  edge = libmesh_make_unique<InfEdge2>();
226  break;
227  }
228 
229  default:
230  libmesh_error_msg("Invalid side i = " << i);
231  }
232 
233  edge->subdomain_id() = this->subdomain_id();
234 
235  // Set the nodes
236  for (unsigned n=0; n<edge->n_nodes(); ++n)
237  edge->set_node(n) = this->node_ptr(InfQuad4::side_nodes_map[i][n]);
238 
239  return edge;
240  }
241 }
242 
243 
244 
245 void InfQuad4::build_side_ptr (std::unique_ptr<Elem> & side,
246  const unsigned int i)
247 {
248  libmesh_assert_less (i, this->n_sides());
249 
250  // Think of a unit cube: (-1,1) x (-1,1) x (1,1)
251  switch (i)
252  {
253  // the base face
254  case 0:
255  {
256  if (!side.get() || side->type() != EDGE2)
257  {
258  side = this->build_side_ptr(i, false);
259  return;
260  }
261  break;
262  }
263 
264  // connecting to another infinite element
265  case 1:
266  case 2:
267  {
268  if (!side.get() || side->type() != INFEDGE2)
269  {
270  side = this->build_side_ptr(i, false);
271  return;
272  }
273  break;
274  }
275 
276  default:
277  libmesh_error_msg("Invalid side i = " << i);
278  }
279 
280  side->subdomain_id() = this->subdomain_id();
281 
282  // Set the nodes
283  for (auto n : side->node_index_range())
284  side->set_node(n) = this->node_ptr(InfQuad4::side_nodes_map[i][n]);
285 }
286 
287 
288 
289 void InfQuad4::connectivity(const unsigned int libmesh_dbg_var(sf),
290  const IOPackage iop,
291  std::vector<dof_id_type> & conn) const
292 {
293  libmesh_assert_less (sf, this->n_sub_elem());
294  libmesh_assert_not_equal_to (iop, INVALID_IO_PACKAGE);
295 
296  conn.resize(4);
297 
298  switch (iop)
299  {
300  case TECPLOT:
301  {
302  conn[0] = this->node_id(0)+1;
303  conn[1] = this->node_id(1)+1;
304  conn[2] = this->node_id(3)+1;
305  conn[3] = this->node_id(2)+1;
306  return;
307  }
308  case VTK:
309  {
310  conn[0] = this->node_id(0);
311  conn[1] = this->node_id(1);
312  conn[2] = this->node_id(3);
313  conn[3] = this->node_id(2);
314  return;
315  }
316  default:
317  libmesh_error_msg("Unsupported IO package " << iop);
318  }
319 }
320 
321 } // namespace libMesh
322 
323 
324 #endif // ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
Manages the family, order, etc. parameters for a given FE.
Definition: fe_type.h:179
static const float _embedding_matrix[num_children][num_nodes][num_nodes]
virtual bool contains_point(const Point &p, Real tol=TOLERANCE) const override
static const int num_children
virtual ElemType type() const override
static const unsigned int side_nodes_map[num_sides][nodes_per_side]
virtual bool is_vertex(const unsigned int i) const override
unsigned short int side
Definition: xdr_io.C:50
IterBase * end
virtual Point origin() const override final
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const override
virtual unsigned short dim() const override final
Definition: face_inf_quad.h:95
static Point inverse_map(const unsigned int dim, const FEType &fe_t, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition: fe_interface.C:590
virtual void connectivity(const unsigned int sf, const IOPackage iop, std::vector< dof_id_type > &conn) const override
static const int num_sides
static bool on_reference_element(const Point &p, const ElemType t, const Real eps=TOLERANCE)
Definition: fe_interface.C:647
Real norm_sq() const
Definition: type_vector.h:943
virtual bool is_face(const unsigned int i) const override
virtual Order default_order() const override
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
subdomain_id_type subdomain_id() const
Definition: elem.h:2034
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:1957
virtual unsigned int n_sides() const override final
virtual bool is_edge(const unsigned int i) const override
static const int nodes_per_side
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i, bool proxy) override
virtual std::vector< unsigned int > nodes_on_side(const unsigned int s) const override
virtual unsigned int n_sub_elem() const override
static const int num_nodes
long double min(long double a, double b)
A geometric point in (x,y,z) space.
Definition: point.h:38
dof_id_type node_id(const unsigned int i) const
Definition: elem.h:1914
const Point & point(const unsigned int i) const
Definition: elem.h:1892
std::unique_ptr< Elem > side(const unsigned int i) const
Definition: elem.h:2202