inf_elem_builder.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 #include "libmesh/libmesh_config.h"
19 
20 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
21 
22 // C++ includes
23 
24 // Local includes
27 #include "libmesh/mesh_tools.h"
28 #include "libmesh/face_inf_quad4.h"
29 #include "libmesh/face_inf_quad6.h"
32 #include "libmesh/cell_inf_hex8.h"
33 #include "libmesh/cell_inf_hex16.h"
34 #include "libmesh/cell_inf_hex18.h"
35 #include "libmesh/mesh_base.h"
36 #include "libmesh/remote_elem.h"
37 
38 namespace libMesh
39 {
40 
41 const Point InfElemBuilder::build_inf_elem(bool be_verbose)
42 {
43  // determine origin automatically,
44  // works only if the mesh has no symmetry planes.
46  Point origin = (b_box.first + b_box.second) / 2;
47 
48  if (be_verbose && _mesh.processor_id() == 0)
49  {
50 #ifdef DEBUG
51  libMesh::out << " Determined origin for Infinite Elements:"
52  << std::endl
53  << " ";
55  libMesh::out << std::endl;
56 #endif
57  }
58 
59  // Call the protected implementation function with the
60  // automatically determined origin.
61  this->build_inf_elem(origin, false, false, false, be_verbose);
62 
63  // when finished with building the Ifems,
64  // it remains to prepare the mesh for use:
65  // find neighbors (again), partition (if needed)...
66  this->_mesh.prepare_for_use (/*skip_renumber =*/ false);
67 
68  return origin;
69 }
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
83  const InfElemOriginValue & origin_y,
84  const InfElemOriginValue & origin_z,
85  const bool x_sym,
86  const bool y_sym,
87  const bool z_sym,
88  const bool be_verbose,
89  std::vector<const Node *> * inner_boundary_nodes)
90 {
91  START_LOG("build_inf_elem()", "InfElemBuilder");
92 
93  // first determine the origin of the
94  // infinite elements. For this, the
95  // origin defaults to the given values,
96  // and may be overridden when the user
97  // provided values
98  Point origin(origin_x.second, origin_y.second, origin_z.second);
99 
100  // when only _one_ of the origin coordinates is _not_
101  // given, we have to determine it on our own
102  if ( !origin_x.first || !origin_y.first || !origin_z.first)
103  {
104  // determine origin
106  const Point auto_origin = (b_box.first+b_box.second)/2;
107 
108  // override default values, if necessary
109  if (!origin_x.first)
110  origin(0) = auto_origin(0);
111  if (!origin_y.first)
112  origin(1) = auto_origin(1);
113  if (!origin_z.first)
114  origin(2) = auto_origin(2);
115 
116  if (be_verbose)
117  {
118  libMesh::out << " Origin for Infinite Elements:" << std::endl;
119 
120  if (!origin_x.first)
121  libMesh::out << " determined x-coordinate" << std::endl;
122  if (!origin_y.first)
123  libMesh::out << " determined y-coordinate" << std::endl;
124  if (!origin_z.first)
125  libMesh::out << " determined z-coordinate" << std::endl;
126 
127  libMesh::out << " coordinates: ";
129  libMesh::out << std::endl;
130  }
131  }
132 
133  else if (be_verbose)
134 
135  {
136  libMesh::out << " Origin for Infinite Elements:" << std::endl;
137  libMesh::out << " coordinates: ";
139  libMesh::out << std::endl;
140  }
141 
142 
143 
144  // Now that we have the origin, check if the user provided an \p
145  // inner_boundary_nodes. If so, we pass a std::set to the actual
146  // implementation of the build_inf_elem(), so that we can convert
147  // this to the Node * vector
148  if (inner_boundary_nodes != nullptr)
149  {
150  // note that the std::set that we will get
151  // from build_inf_elem() uses the index of
152  // the element in this->_elements vector,
153  // and the second entry is the side index
154  // for this element. Therefore, we do _not_
155  // need to renumber nodes and elements
156  // prior to building the infinite elements.
157  //
158  // However, note that this method here uses
159  // node id's... Do we need to renumber?
160 
161 
162  // Form the list of faces of elements which finally
163  // will tell us which nodes should receive boundary
164  // conditions (to form the std::vector<const Node *>)
165  std::set<std::pair<dof_id_type,
166  unsigned int>> inner_faces;
167 
168 
169  // build infinite elements
170  this->build_inf_elem(origin,
171  x_sym, y_sym, z_sym,
172  be_verbose,
173  &inner_faces);
174 
175  if (be_verbose)
176  {
177  this->_mesh.print_info();
178  libMesh::out << "Data pre-processing:" << std::endl
179  << " convert the <int,int> list to a Node * list..."
180  << std::endl;
181  }
182 
183  // First use a std::vector<dof_id_type> that holds
184  // the global node numbers. Then sort this vector,
185  // so that it can be made unique (no multiple occurrence
186  // of a node), and then finally insert the Node * in
187  // the vector inner_boundary_nodes.
188  //
189  // Reserve memory for the vector<> with
190  // 4 times the size of the number of elements in the
191  // std::set. This is a good bet for Quad4 face elements.
192  // For higher-order elements, this probably _has_ to lead
193  // to additional allocations...
194  // Practice has to show how this affects performance.
195  std::vector<dof_id_type> inner_boundary_node_numbers;
196  inner_boundary_node_numbers.reserve(4*inner_faces.size());
197 
198  // Now transform the set of pairs to a list of (possibly
199  // duplicate) global node numbers.
200  std::set<std::pair<dof_id_type,unsigned int>>::iterator face_it = inner_faces.begin();
201  const std::set<std::pair<dof_id_type,unsigned int>>::iterator face_end = inner_faces.end();
202  for (; face_it!=face_end; ++face_it)
203  {
204  std::pair<dof_id_type,unsigned int> p = *face_it;
205 
206  // build a full-ordered side element to get _all_ the base nodes
207  std::unique_ptr<Elem> side(this->_mesh.elem_ref(p.first).build_side_ptr(p.second));
208 
209  // insert all the node numbers in inner_boundary_node_numbers
210  for (unsigned int n=0; n<side->n_nodes(); n++)
211  inner_boundary_node_numbers.push_back(side->node_id(n));
212  }
213 
214 
215  // inner_boundary_node_numbers now still holds multiple entries of
216  // node numbers. So first sort, then unique the vector.
217  // Note that \p std::unique only puts the new ones in
218  // front, while to leftovers are not deleted. Instead,
219  // it returns a pointer to the end of the unique range.
220  //TODO:[BSK] int_ibn_size_before is not the same type as unique_size!
221 #ifndef NDEBUG
222  const std::size_t ibn_size_before = inner_boundary_node_numbers.size();
223 #endif
224  std::sort (inner_boundary_node_numbers.begin(), inner_boundary_node_numbers.end());
225  std::vector<dof_id_type>::iterator unique_end =
226  std::unique (inner_boundary_node_numbers.begin(), inner_boundary_node_numbers.end());
227 
228  std::size_t unique_size = std::distance(inner_boundary_node_numbers.begin(), unique_end);
229  libmesh_assert_less_equal (unique_size, ibn_size_before);
230 
231  // Finally, create const Node * in the inner_boundary_nodes
232  // vector. Reserve, not resize (otherwise, the push_back
233  // would append the interesting nodes, while nullptr-nodes
234  // live in the resize'd area...
235  inner_boundary_nodes->reserve (unique_size);
236  inner_boundary_nodes->clear();
237 
238 
239  std::vector<dof_id_type>::iterator pos_it = inner_boundary_node_numbers.begin();
240  for (; pos_it != unique_end; ++pos_it)
241  {
242  const Node * node = this->_mesh.node_ptr(*pos_it);
243  inner_boundary_nodes->push_back(node);
244  }
245 
246  if (be_verbose)
247  libMesh::out << " finished identifying " << unique_size
248  << " target nodes." << std::endl;
249  }
250 
251  else
252 
253  {
254  // There are no inner boundary nodes, so simply build the infinite elements
255  this->build_inf_elem(origin, x_sym, y_sym, z_sym, be_verbose);
256  }
257 
258 
259  STOP_LOG("build_inf_elem()", "InfElemBuilder");
260 
261  // when finished with building the Ifems,
262  // it remains to prepare the mesh for use:
263  // find neighbors again, partition (if needed)...
264  this->_mesh.prepare_for_use (/*skip_renumber =*/ false);
265 
266  return origin;
267 }
268 
269 
270 
271 
272 
273 
274 
275 
276 
277 // The actual implementation of building elements.
279  const bool x_sym,
280  const bool y_sym,
281  const bool z_sym,
282  const bool be_verbose,
283  std::set<std::pair<dof_id_type,
284  unsigned int>> * inner_faces)
285 {
286  if (be_verbose)
287  {
288 #ifdef DEBUG
289  libMesh::out << " Building Infinite Elements:" << std::endl;
290  libMesh::out << " updating element neighbor tables..." << std::endl;
291 #else
292  libMesh::out << " Verbose mode disabled in non-debug mode." << std::endl;
293 #endif
294  }
295 
296 
297  // update element neighbors
298  this->_mesh.find_neighbors();
299 
300  LOG_SCOPE("build_inf_elem()", "InfElemBuilder");
301 
302  // A set for storing element number, side number pairs.
303  // pair.first == element number, pair.second == side number
304  std::set<std::pair<dof_id_type,unsigned int>> faces;
305  std::set<std::pair<dof_id_type,unsigned int>> ofaces;
306 
307  // A set for storing node numbers on the outer faces.
308  std::set<dof_id_type> onodes;
309 
310  // The distance to the farthest point in the mesh from the origin
311  Real max_r=0.;
312 
313  // The index of the farthest point in the mesh from the origin
314  int max_r_node = -1;
315 
316 #ifdef DEBUG
317  if (be_verbose)
318  {
319  libMesh::out << " collecting boundary sides";
320  if (x_sym || y_sym || z_sym)
321  libMesh::out << ", skipping sides in symmetry planes..." << std::endl;
322  else
323  libMesh::out << "..." << std::endl;
324  }
325 #endif
326 
327  // Iterate through all elements and sides, collect indices of all active
328  // boundary sides in the faces set. Skip sides which lie in symmetry planes.
329  // Later, sides of the inner boundary will be sorted out.
330  for (const auto & elem : _mesh.active_element_ptr_range())
331  for (auto s : elem->side_index_range())
332  if (elem->neighbor_ptr(s) == nullptr)
333  {
334  // note that it is safe to use the Elem::side() method,
335  // which gives a non-full-ordered element
336  std::unique_ptr<Elem> side(elem->build_side_ptr(s));
337 
338  // bool flags for symmetry detection
339  bool sym_side=false;
340  bool on_x_sym=true;
341  bool on_y_sym=true;
342  bool on_z_sym=true;
343 
344 
345  // Loop over the nodes to check whether they are on the symmetry planes,
346  // and therefore sufficient to use a non-full-ordered side element
347  for (unsigned int n=0; n<side->n_nodes(); n++)
348  {
349  const Point dist_from_origin =
350  this->_mesh.point(side->node_id(n)) - origin;
351 
352  if (x_sym)
353  if (std::abs(dist_from_origin(0)) > 1.e-3)
354  on_x_sym=false;
355 
356  if (y_sym)
357  if (std::abs(dist_from_origin(1)) > 1.e-3)
358  on_y_sym=false;
359 
360  if (z_sym)
361  if (std::abs(dist_from_origin(2)) > 1.e-3)
362  on_z_sym=false;
363 
364  // if (x_sym)
365  // if (std::abs(dist_from_origin(0)) > 1.e-6)
366  // on_x_sym=false;
367 
368  // if (y_sym)
369  // if (std::abs(dist_from_origin(1)) > 1.e-6)
370  // on_y_sym=false;
371 
372  // if (z_sym)
373  // if (std::abs(dist_from_origin(2)) > 1.e-6)
374  // on_z_sym=false;
375 
376  //find the node most distant from origin
377 
378  Real r = dist_from_origin.norm();
379  if (r > max_r)
380  {
381  max_r = r;
382  max_r_node=side->node_id(n);
383  }
384 
385  }
386 
387  sym_side = (x_sym && on_x_sym) || (y_sym && on_y_sym) || (z_sym && on_z_sym);
388 
389  if (!sym_side)
390  faces.insert( std::make_pair(elem->id(), s) );
391 
392  } // neighbor(s) == nullptr
393 
394 
395 
396 
397 
398 
399  // If a boundary side has one node on the outer boundary,
400  // all points of this side are on the outer boundary.
401  // Start with the node most distant from origin, which has
402  // to be on the outer boundary, then recursively find all
403  // sides and nodes connected to it. Found sides are moved
404  // from faces to ofaces, nodes are collected in onodes.
405  // Here, the search is done iteratively, because, depending on
406  // the mesh, a very high level of recursion might be necessary.
407  if (max_r_node >= 0)
408  // include the possibility of the 1st element being most far away.
409  // Only the case of no outer boundary is to be excluded.
410  onodes.insert(max_r_node);
411 
412 
413  {
414  auto face_it = faces.begin();
415  auto face_end = faces.end();
416  unsigned int facesfound=0;
417  while (face_it != face_end) {
418  std::pair<dof_id_type, unsigned int> p = *face_it;
419 
420  // This has to be a full-ordered side element,
421  // since we need the correct n_nodes,
422  std::unique_ptr<Elem> side(this->_mesh.elem_ref(p.first).build_side_ptr(p.second));
423 
424  bool found=false;
425  for (unsigned int sn=0; sn<side->n_nodes(); sn++)
426  if (onodes.count(side->node_id(sn)))
427  {
428  found=true;
429  break;
430  }
431 
432  // If a new oface is found, include its nodes in onodes
433  if (found)
434  {
435  for (unsigned int sn=0; sn<side->n_nodes(); sn++)
436  onodes.insert(side->node_id(sn));
437 
438  ofaces.insert(p);
439  face_it = faces.erase(face_it); // increment is done here
440 
441  facesfound++;
442  }
443 
444  else
445  ++face_it; // increment is done here
446 
447  // If at least one new oface was found in this cycle,
448  // do another search cycle.
449  if (facesfound>0 && face_it == faces.end())
450  {
451  facesfound = 0;
452  face_it = faces.begin();
453  }
454  }
455  }
456 
457 
458 #ifdef DEBUG
459  if (be_verbose)
460  libMesh::out << " found "
461  << faces.size()
462  << " inner and "
463  << ofaces.size()
464  << " outer boundary faces"
465  << std::endl;
466 #endif
467 
468  // When the user provided a non-null pointer to
469  // inner_faces, that implies he wants to have
470  // this std::set. For now, simply copy the data.
471  if (inner_faces != nullptr)
472  *inner_faces = faces;
473 
474  // free memory, clear our local variable, no need
475  // for it any more.
476  faces.clear();
477 
478 
479  // outer_nodes maps onodes to their duplicates
480  std::map<dof_id_type, Node *> outer_nodes;
481 
482  // We may need to pick our own object ids in parallel
483  dof_id_type old_max_node_id = _mesh.max_node_id();
484  dof_id_type old_max_elem_id = _mesh.max_elem_id();
485 
486  // Likewise with our unique_ids
487 #ifdef LIBMESH_ENABLE_UNIQUE_ID
488  unique_id_type old_max_unique_id = _mesh.parallel_max_unique_id();
489 #endif
490 
491  // for each boundary node, add an outer_node with
492  // double distance from origin.
493  std::set<dof_id_type>::iterator on_it = onodes.begin();
494  for ( ; on_it != onodes.end(); ++on_it)
495  {
496  Point p = (Point(this->_mesh.point(*on_it)) * 2) - origin;
497  if (_mesh.is_serial())
498  {
499  // Add with a default id in serial
500  outer_nodes[*on_it]=this->_mesh.add_point(p);
501  }
502  else
503  {
504  // Pick a unique id in parallel
505  Node & bnode = _mesh.node_ref(*on_it);
506  dof_id_type new_id = bnode.id() + old_max_node_id;
507  Node * new_node =
508  this->_mesh.add_point(p, new_id,
509  bnode.processor_id());
510 #ifdef LIBMESH_ENABLE_UNIQUE_ID
511  new_node->set_unique_id() = old_max_unique_id + bnode.id();
512 #endif
513  outer_nodes[*on_it] = new_node;
514  }
515  }
516 
517 
518 #ifdef DEBUG
519  // for verbose, remember n_elem
520  dof_id_type n_conventional_elem = this->_mesh.n_elem();
521 #endif
522 
523 
524  // build Elems based on boundary side type
525  for (auto & p : ofaces)
526  {
527  Elem & belem = this->_mesh.elem_ref(p.first);
528 
529  // build a full-ordered side element to get the base nodes
530  std::unique_ptr<Elem> side(belem.build_side_ptr(p.second));
531 
532  // create cell depending on side type, assign nodes,
533  // use braces to force scope.
534  bool is_higher_order_elem = false;
535 
536  Elem * el;
537  switch(side->type())
538  {
539  // 3D infinite elements
540  // TRIs
541  case TRI3:
542  el=new InfPrism6;
543  break;
544 
545  case TRI6:
546  el=new InfPrism12;
547  is_higher_order_elem = true;
548  break;
549 
550  // QUADs
551  case QUAD4:
552  el=new InfHex8;
553  break;
554 
555  case QUAD8:
556  el=new InfHex16;
557  is_higher_order_elem = true;
558  break;
559 
560  case QUAD9:
561  el=new InfHex18;
562 
563  // the method of assigning nodes (which follows below)
564  // omits in the case of QUAD9 the bubble node; therefore
565  // we assign these first by hand here.
566  el->set_node(16) = side->node_ptr(8);
567  el->set_node(17) = outer_nodes[side->node_id(8)];
568  is_higher_order_elem=true;
569  break;
570 
571  // 2D infinite elements
572  case EDGE2:
573  el=new InfQuad4;
574  break;
575 
576  case EDGE3:
577  el=new InfQuad6;
578  el->set_node(4) = side->node_ptr(2);
579  break;
580 
581  // 1D infinite elements not supported
582  default:
583  libMesh::out << "InfElemBuilder::build_inf_elem(Point, bool, bool, bool, bool): "
584  << "invalid face element "
585  << std::endl;
586  continue;
587  }
588 
589  const unsigned int n_base_vertices = side->n_vertices();
590 
591  // On a distributed mesh, manually assign unique ids to the new
592  // element, and make sure any RemoteElem neighbor links are set.
593  if (!_mesh.is_serial())
594  {
595  el->processor_id() = belem.processor_id();
596 
597  // We'd better not have elements with more than 6 sides
598  libmesh_assert_less_equal(el->n_sides(), 6);
599  el->set_id (belem.id() * 6 + p.second + old_max_elem_id);
600 
601 #ifdef LIBMESH_ENABLE_UNIQUE_ID
602  el->set_unique_id() = old_max_unique_id + old_max_node_id + belem.id();
603 #endif
604 
605  // If we have a remote neighbor on a boundary element side
606  if (belem.dim() > 1)
607  for (auto s : belem.side_index_range())
608  if (belem.neighbor_ptr(s) == remote_elem)
609  {
610  // Find any corresponding infinite element side
611  std::unique_ptr<const Elem> remote_side(belem.build_side_ptr(s));
612 
613  for (auto inf_s : el->side_index_range())
614  {
615  // The base side 0 shares all vertices but isn't
616  // remote
617  if (!inf_s)
618  continue;
619 
620  // But another side, one which shares enough
621  // vertices to show it's the same side, is.
622  unsigned int n_shared_vertices = 0;
623  for (unsigned int i = 0; i != n_base_vertices; ++i)
624  for (auto & node : remote_side->node_ref_range())
625  if (side->node_ptr(i) == &node &&
626  el->is_node_on_side(i,inf_s))
627  ++n_shared_vertices;
628 
629  if (n_shared_vertices + 1 >= belem.dim())
630  {
631  el->set_neighbor
632  (inf_s, const_cast<RemoteElem *>(remote_elem));
633  break;
634  }
635  }
636  }
637  }
638 
639  // assign vertices to the new infinite element
640  for (unsigned int i=0; i<n_base_vertices; i++)
641  {
642  el->set_node(i ) = side->node_ptr(i);
643  el->set_node(i+n_base_vertices) = outer_nodes[side->node_id(i)];
644  }
645 
646 
647  // when this is a higher order element,
648  // assign also the nodes in between
649  if (is_higher_order_elem)
650  {
651  // n_safe_base_nodes is the number of nodes in \p side
652  // that may be safely assigned using below for loop.
653  // Actually, n_safe_base_nodes is _identical_ with el->n_vertices(),
654  // since for QUAD9, the 9th node was already assigned above
655  const unsigned int n_safe_base_nodes = el->n_vertices();
656 
657  for (unsigned int i=n_base_vertices; i<n_safe_base_nodes; i++)
658  {
659  el->set_node(i+n_base_vertices) = side->node_ptr(i);
660  el->set_node(i+n_safe_base_nodes) =
661  outer_nodes[side->node_id(i)];
662  }
663  }
664 
665 
666  // add infinite element to mesh
667  this->_mesh.add_elem(el);
668  } // for
669 
670 
671 #ifdef DEBUG
673 
674  if (be_verbose)
675  libMesh::out << " added "
676  << this->_mesh.n_elem() - n_conventional_elem
677  << " infinite elements and "
678  << onodes.size()
679  << " nodes to the mesh"
680  << std::endl
681  << std::endl;
682 #endif
683 }
684 
685 } // namespace libMesh
686 
687 
688 
689 
690 
691 #endif // LIBMESH_ENABLE_INFINITE_ELEMENTS
double abs(double a)
unique_id_type & set_unique_id()
Definition: dof_object.h:685
A 3D infinite hexahedral element with 8 nodes.
Definition: cell_inf_hex8.h:55
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2024
A geometric point in (x,y,z) space associated with a DOF.
Definition: node.h:52
virtual unique_id_type parallel_max_unique_id() const =0
Real norm() const
Definition: type_vector.h:912
IntRange< unsigned short > side_index_range() const
Definition: elem.h:2166
libMesh::BoundingBox create_bounding_box(const MeshBase &mesh)
Definition: mesh_tools.C:386
A 2D infinite quadrilateral element with 4 nodes.
unsigned short int side
Definition: xdr_io.C:50
The base class for all geometric element types.
Definition: elem.h:100
virtual bool is_node_on_side(const unsigned int n, const unsigned int s) const =0
virtual SimpleRange< element_iterator > active_element_ptr_range()=0
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
dof_id_type & set_id()
Definition: dof_object.h:664
virtual std::unique_ptr< Elem > build_side_ptr(const unsigned int i, bool proxy=true)=0
virtual bool is_serial() const
Definition: mesh_base.h:154
virtual void find_neighbors(const bool reset_remote_elements=false, const bool reset_current_list=true)=0
void write_unformatted(std::ostream &out, const bool newline=true) const
Definition: type_vector.C:92
std::pair< bool, double > InfElemOriginValue
dof_id_type id() const
Definition: dof_object.h:655
A 3D infinite prismatic element with 12 nodes.
A 3D infinite hexahedral element with 16 nodes.
virtual Elem * add_elem(Elem *e)=0
virtual dof_id_type max_elem_id() const =0
void prepare_for_use(const bool skip_renumber_nodes_and_elements=false, const bool skip_find_neighbors=false)
Definition: mesh_base.C:152
A 2D infinite quadrilateral element with 6 nodes.
void set_neighbor(const unsigned int i, Elem *n)
Definition: elem.h:2083
virtual unsigned int n_sides() const =0
const Elem * neighbor_ptr(unsigned int i) const
Definition: elem.h:2050
virtual unsigned int n_vertices() const =0
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
const Point build_inf_elem(const bool be_verbose=false)
virtual unsigned short dim() const =0
virtual const Elem & elem_ref(const dof_id_type i) const
Definition: mesh_base.h:504
A 3D infinite prismatic element with 6 nodes.
virtual void libmesh_assert_valid_parallel_ids() const
Definition: mesh_base.h:1007
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:434
virtual const Point & point(const dof_id_type i) const =0
void print_info(std::ostream &os=libMesh::out) const
Definition: mesh_base.C:412
virtual dof_id_type max_node_id() const =0
virtual dof_id_type n_elem() const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
processor_id_type processor_id() const
OStreamProxy out(std::cout)
processor_id_type processor_id() const
Definition: dof_object.h:717
A geometric point in (x,y,z) space.
Definition: point.h:38
uint8_t unique_id_type
Definition: id_types.h:79
A 3D infinite hexahedral element with 18 nodes.
uint8_t dof_id_type
Definition: id_types.h:64
const RemoteElem * remote_elem
Definition: remote_elem.C:57