bool MeshRefinement::eliminate_unrefined_patches ()
{
  // This function must be run on all processors at once
  parallel_only();

  bool flags_changed = false;

  MeshBase::element_iterator       elem_it  = _mesh.active_elements_begin();
  const MeshBase::element_iterator elem_end = _mesh.active_elements_end();

  for (; elem_it != elem_end; ++elem_it)
    {
      Elem* elem = *elem_it;
      // First assume that we'll have to flag this element for both h
      // and p refinement, then change our minds if we see any
      // neighbors that are as coarse or coarser than us.
      bool h_flag_me = true,
           p_flag_me = true;


      // Skip the element if it is already fully flagged for refinement
      if (elem->p_refinement_flag() == Elem::REFINE)
	p_flag_me = false;
      if (elem->refinement_flag() == Elem::REFINE)
        {
          h_flag_me = false;
          if (!p_flag_me)
            continue;
        }
      // Test the parent if that is already flagged for coarsening
      else if (elem->refinement_flag() == Elem::COARSEN)
        {
          libmesh_assert(elem->parent());
	  elem = elem->parent();
          // FIXME - this doesn't seem right - RHS
          if (elem->refinement_flag() != Elem::COARSEN_INACTIVE)
            continue;
          p_flag_me = false;
        }

      const unsigned int my_level = elem->level();
      int my_p_adjustment = 0;
      if (elem->p_refinement_flag() == Elem::REFINE)
        my_p_adjustment = 1;
      else if (elem->p_refinement_flag() == Elem::COARSEN)
        {
          libmesh_assert_greater (elem->p_level(), 0);
          my_p_adjustment = -1;
        }
      const unsigned int my_new_p_level = elem->p_level() +
                                          my_p_adjustment;

      // Check all the element neighbors
      for (unsigned int n=0; n<elem->n_neighbors(); n++)
        {
          const Elem *neighbor = elem->neighbor(n);
	  // Quit if the element is on a local boundary
	  if (neighbor == NULL || neighbor == remote_elem)
            {
              h_flag_me = false;
              p_flag_me = false;
              break;
            }
          // if the neighbor will be equally or less refined than
	  // we are, then we will not become an unrefined island.
          // So if we are still considering h refinement:
          if (h_flag_me &&
            // If our neighbor is already at a lower level,
            // it can't end up at a higher level even if it
            // is flagged for refinement once
             ((neighbor->level() < my_level) ||
            // If our neighbor is at the same level but isn't
            // flagged for refinement, it won't end up at a
            // higher level
             ((neighbor->active()) &&
              (neighbor->refinement_flag() != Elem::REFINE)) ||
            // If our neighbor is currently more refined but is
            // a parent flagged for coarsening, it will end up
            // at the same level.
             (neighbor->refinement_flag() == Elem::COARSEN_INACTIVE)))
            {
              // We've proven we won't become an unrefined island,
              // so don't h refine to avoid that.
	      h_flag_me = false;

              // If we've also proven we don't need to p refine,
              // we don't need to check more neighbors
              if (!p_flag_me)
                break;
            }
	  if (p_flag_me)
            {
	      // if active neighbors will have a p level
	      // equal to or lower than ours, then we do not need to p
              // refine ourselves.
              if (neighbor->active())
                {
                  int p_adjustment = 0;
                  if (neighbor->p_refinement_flag() == Elem::REFINE)
                    p_adjustment = 1;
                  else if (neighbor->p_refinement_flag() == Elem::COARSEN)
                    {
                      libmesh_assert_greater (neighbor->p_level(), 0);
                      p_adjustment = -1;
                    }
                  if (my_new_p_level >= neighbor->p_level() + p_adjustment)
                    {
                      p_flag_me = false;
                      if (!h_flag_me)
                        break;
                    }
                }
              // If we have inactive neighbors, we need to
              // test all their active descendants which neighbor us
              else if (neighbor->ancestor())
                {
                  if (neighbor->min_new_p_level_by_neighbor(elem,
                      my_new_p_level + 2) <= my_new_p_level)
                    {
                      p_flag_me = false;
                      if (!h_flag_me)
                        break;
                    }
                }
            }
        }

      if (h_flag_me)
	{
	  // Parents that would create islands should no longer
          // coarsen
          if (elem->refinement_flag() == Elem::COARSEN_INACTIVE)
            {
              for (unsigned int c=0; c<elem->n_children(); c++)
                {
                  libmesh_assert_equal_to (elem->child(c)->refinement_flag(),
                                          Elem::COARSEN);
                  elem->child(c)->set_refinement_flag(Elem::DO_NOTHING);
                }
              elem->set_refinement_flag(Elem::INACTIVE);
            }
          else
	    elem->set_refinement_flag(Elem::REFINE);
	  flags_changed = true;
	}
      if (p_flag_me)
	{
          if (elem->p_refinement_flag() == Elem::COARSEN)
	    elem->set_p_refinement_flag(Elem::DO_NOTHING);
          else
	    elem->set_p_refinement_flag(Elem::REFINE);
	  flags_changed = true;
	}
    }

  // If flags changed on any processor then they changed globally
  CommWorld.max(flags_changed);

  return flags_changed;
}
예제 #2
0
void add_cube_convex_hull_to_mesh(MeshBase& mesh, Point lower_limit, Point upper_limit)
{
#ifdef LIBMESH_HAVE_TETGEN
  SerialMesh cube_mesh(3);

  unsigned n_elem = 1;

  MeshTools::Generation::build_cube(cube_mesh,
				    n_elem,n_elem,n_elem, // n. elements in each direction
				    lower_limit(0), upper_limit(0),
				    lower_limit(1), upper_limit(1),
				    lower_limit(2), upper_limit(2),
				    HEX8);
  
  // The pointset_convexhull() algorithm will ignore the Hex8s
  // in the Mesh, and just construct the triangulation
  // of the convex hull.
  TetGenMeshInterface t(cube_mesh);
  t.pointset_convexhull(); 
  
  // Now add all nodes from the boundary of the cube_mesh to the input mesh.

  // Map from "node id in cube_mesh" -> "node id in mesh".  Initially inserted
  // with a dummy value, later to be assigned a value by the input mesh.
  std::map<unsigned,unsigned> node_id_map;
  typedef std::map<unsigned,unsigned>::iterator iterator;

  {
    MeshBase::element_iterator it = cube_mesh.elements_begin();
    const MeshBase::element_iterator end = cube_mesh.elements_end();
    for ( ; it != end; ++it) 
      {
	Elem* elem = *it;
	  
	for (unsigned s=0; s<elem->n_sides(); ++s)
	  if (elem->neighbor(s) == NULL)
	    {
	      // Add the node IDs of this side to the set
	      AutoPtr<Elem> side = elem->side(s);
		
	      for (unsigned n=0; n<side->n_nodes(); ++n)
		node_id_map.insert( std::make_pair(side->node(n), /*dummy_value=*/0) );
	    }
      }
  }

  // For each node in the map, insert it into the input mesh and keep 
  // track of the ID assigned.
  for (iterator it=node_id_map.begin(); it != node_id_map.end(); ++it)
    {
      // Id of the node in the cube mesh
      unsigned id = (*it).first;

      // Pointer to node in the cube mesh
      Node* old_node = cube_mesh.node_ptr(id);

      // Add geometric point to input mesh
      Node* new_node = mesh.add_point ( *old_node );

      // Track ID value of new_node in map
      (*it).second = new_node->id();
    }
  
  // With the points added and the map data structure in place, we are
  // ready to add each TRI3 element of the cube_mesh to the input Mesh 
  // with proper node assignments
  {
    MeshBase::element_iterator       el     = cube_mesh.elements_begin();
    const MeshBase::element_iterator end_el = cube_mesh.elements_end();
    
    for (; el != end_el; ++el)
      {
	Elem* old_elem = *el;

	if (old_elem->type() == TRI3)
	  {
	    Elem* new_elem = mesh.add_elem(new Tri3);

	    // Assign nodes in new elements.  Since this is an example,
	    // we'll do it in several steps.
	    for (unsigned i=0; i<old_elem->n_nodes(); ++i)
	      {
		// Locate old node ID in the map
		iterator it = node_id_map.find(old_elem->node(i));

		// Check for not found
		if (it == node_id_map.end())
		  {
		    libMesh::err << "Node id " << old_elem->node(i) << " not found in map!" << std::endl;
		    libmesh_error();
		  }

		// Mapping to node ID in input mesh
		unsigned new_node_id = (*it).second;

		// Node pointer assigned from input mesh
		new_elem->set_node(i) = mesh.node_ptr(new_node_id);
	      }
	  }
      }
  }
#endif // LIBMESH_HAVE_TETGEN
}
예제 #3
0
int main(int argc, char** argv)
{
    LibMeshInit init(argc, argv);

    GetPot cl(argc, argv);

    int dim = -1;
    if (!cl.search("--dim"))
    {
        std::cerr << "No --dim argument found!" << std::endl;
        usage_error(argv[0]);
    }
    dim = cl.next(dim);

    Mesh mesh(dim);

    if(!cl.search("--input"))
    {
        std::cerr << "No --input argument found!" << std::endl;
        usage_error(argv[0]);
    }
    const char* meshname = cl.next("mesh.xda");

    mesh.read(meshname);
    std::cout << "Loaded mesh " << meshname << std::endl;

    if(!cl.search("--newbcid"))
    {
        std::cerr << "No --bcid argument found!" << std::endl;
        usage_error(argv[0]);
    }
    boundary_id_type bcid = 0;
    bcid = cl.next(bcid);

    Point minnormal(-std::numeric_limits<Real>::max(),
                    -std::numeric_limits<Real>::max(),
                    -std::numeric_limits<Real>::max());
    Point maxnormal(std::numeric_limits<Real>::max(),
                    std::numeric_limits<Real>::max(),
                    std::numeric_limits<Real>::max());
    Point minpoint(-std::numeric_limits<Real>::max(),
                   -std::numeric_limits<Real>::max(),
                   -std::numeric_limits<Real>::max());
    Point maxpoint(std::numeric_limits<Real>::max(),
                   std::numeric_limits<Real>::max(),
                   std::numeric_limits<Real>::max());

    if (cl.search("--minnormalx"))
        minnormal(0) = cl.next(minnormal(0));
    if (cl.search("--minnormalx"))
        minnormal(0) = cl.next(minnormal(0));
    if (cl.search("--maxnormalx"))
        maxnormal(0) = cl.next(maxnormal(0));
    if (cl.search("--minnormaly"))
        minnormal(1) = cl.next(minnormal(1));
    if (cl.search("--maxnormaly"))
        maxnormal(1) = cl.next(maxnormal(1));
    if (cl.search("--minnormalz"))
        minnormal(2) = cl.next(minnormal(2));
    if (cl.search("--maxnormalz"))
        maxnormal(2) = cl.next(maxnormal(2));

    if (cl.search("--minpointx"))
        minpoint(0) = cl.next(minpoint(0));
    if (cl.search("--maxpointx"))
        maxpoint(0) = cl.next(maxpoint(0));
    if (cl.search("--minpointy"))
        minpoint(1) = cl.next(minpoint(1));
    if (cl.search("--maxpointy"))
        maxpoint(1) = cl.next(maxpoint(1));
    if (cl.search("--minpointz"))
        minpoint(2) = cl.next(minpoint(2));
    if (cl.search("--maxpointz"))
        maxpoint(2) = cl.next(maxpoint(2));

    std::cout << "min point = " << minpoint << std::endl;
    std::cout << "max point = " << maxpoint << std::endl;
    std::cout << "min normal = " << minnormal << std::endl;
    std::cout << "max normal = " << maxnormal << std::endl;

    bool matcholdbcid = false;
    boundary_id_type oldbcid = 0;
    if (cl.search("--oldbcid"))
    {
        matcholdbcid = true;
        oldbcid = cl.next(oldbcid);
        if (oldbcid < 0)
            oldbcid = BoundaryInfo::invalid_id;
    }

    AutoPtr<FEBase> fe = FEBase::build(dim, FEType(FIRST,LAGRANGE));
    QGauss qface(dim-1, CONSTANT);
    fe->attach_quadrature_rule(&qface);
    const std::vector<Point> &face_points = fe->get_xyz();
    const std::vector<Point> &face_normals = fe->get_normals();

    MeshBase::element_iterator           el = mesh.elements_begin();
    const MeshBase::element_iterator end_el = mesh.elements_end();
    for (; el != end_el; ++el)
    {
        Elem *elem = *el;
        unsigned int n_sides = elem->n_sides();
        for (unsigned int s=0; s != n_sides; ++s)
        {
            if (elem->neighbor(s))
                continue;

            fe->reinit(elem,s);
            const Point &p = face_points[0];
            const Point &n = face_normals[0];

//std::cout << "elem = " << elem->id() << std::endl;
//std::cout << "centroid = " << elem->centroid() << std::endl;
//std::cout << "p = " << p << std::endl;
//std::cout << "n = " << n << std::endl;

            if (p(0) > minpoint(0) && p(0) < maxpoint(0) &&
                    p(1) > minpoint(1) && p(1) < maxpoint(1) &&
                    p(2) > minpoint(2) && p(2) < maxpoint(2) &&
                    n(0) > minnormal(0) && n(0) < maxnormal(0) &&
                    n(1) > minnormal(1) && n(1) < maxnormal(1) &&
                    n(2) > minnormal(2) && n(2) < maxnormal(2))
            {
                if (matcholdbcid &&
                        mesh.boundary_info->boundary_id(elem, s) != oldbcid)
                    continue;
                mesh.boundary_info->remove_side(elem, s);
                mesh.boundary_info->add_side(elem, s, bcid);
//std::cout << "Set element " << elem->id() << " side " << s <<
//             " to boundary " << bcid << std::endl;
            }
        }
    }

    std::string outputname;
    if(cl.search("--output"))
    {
        outputname = cl.next("mesh.xda");
    }
    else
    {
        outputname = "new.";
        outputname += meshname;
    }


    mesh.write(outputname.c_str());
    std::cout << "Wrote mesh " << outputname << std::endl;

    return 0;
}
예제 #4
0
void unpack(std::vector<int>::const_iterator in,
            Elem** out,
            MeshBase* mesh)
{
#ifndef NDEBUG
  const std::vector<int>::const_iterator original_in = in;

  const int incoming_header = *in++;
  libmesh_assert (incoming_header == elem_magic_header);
#endif

  // int 0: level
  const unsigned int level =
    static_cast<unsigned int>(*in++);

#ifdef LIBMESH_ENABLE_AMR
  // int 1: p level
  const unsigned int p_level =
    static_cast<unsigned int>(*in++);

  // int 2: refinement flag
  const int rflag = *in++;
  libmesh_assert(rflag >= 0);
  libmesh_assert(rflag < Elem::INVALID_REFINEMENTSTATE);
  const Elem::RefinementState refinement_flag =
    static_cast<Elem::RefinementState>(rflag);

  // int 3: p refinement flag
  const int pflag = *in++;
  libmesh_assert(pflag >= 0);
  libmesh_assert(pflag < Elem::INVALID_REFINEMENTSTATE);
  const Elem::RefinementState p_refinement_flag =
    static_cast<Elem::RefinementState>(pflag);
#else
  in += 3;
#endif // LIBMESH_ENABLE_AMR

  // int 4: element type
  const int typeint = *in++;
  libmesh_assert(typeint >= 0);
  libmesh_assert(typeint < INVALID_ELEM);
  const ElemType type =
    static_cast<ElemType>(typeint);

  const unsigned int n_nodes = 
    Elem::type_to_n_nodes_map[type];

  // int 5: processor id
  const unsigned int processor_id = 
    static_cast<unsigned int>(*in++);
  libmesh_assert (processor_id < libMesh::n_processors() ||
                  processor_id == DofObject::invalid_processor_id);

  // int 6: subdomain id
  const unsigned int subdomain_id = 
    static_cast<unsigned int>(*in++);

  // int 7: dof object id
  const unsigned int id = 
    static_cast<unsigned int>(*in++);
  libmesh_assert (id != DofObject::invalid_id);

#ifdef LIBMESH_ENABLE_AMR
  // int 8: parent dof object id
  const unsigned int parent_id = 
    static_cast<unsigned int>(*in++);
  libmesh_assert (level == 0 || parent_id != DofObject::invalid_id);
  libmesh_assert (level != 0 || parent_id == DofObject::invalid_id);

  // int 9: local child id
  const unsigned int which_child_am_i = 
    static_cast<unsigned int>(*in++);
#else
  in += 2;
#endif // LIBMESH_ENABLE_AMR

  // Make sure we don't miscount above when adding the "magic" header
  // plus the real data header
  libmesh_assert(in - original_in == header_size + 1);

  Elem *elem = mesh->query_elem(id);

  // if we already have this element, make sure its
  // properties match, and update any missing neighbor
  // links, but then go on
  if (elem) 
    {
      libmesh_assert (elem->level()             == level);
      libmesh_assert (elem->id()                == id);
      libmesh_assert (elem->processor_id()      == processor_id);
      libmesh_assert (elem->subdomain_id()      == subdomain_id);
      libmesh_assert (elem->type()              == type);
      libmesh_assert (elem->n_nodes()           == n_nodes);

#ifndef NDEBUG
      // All our nodes should be correct
      for (unsigned int i=0; i != n_nodes; ++i)
        libmesh_assert(elem->node(i) == 
                       static_cast<unsigned int>(*in++));
#else
      in += n_nodes;
#endif

#ifdef LIBMESH_ENABLE_AMR
      libmesh_assert (elem->p_level()           == p_level);
      libmesh_assert (elem->refinement_flag()   == refinement_flag);
      libmesh_assert (elem->p_refinement_flag() == p_refinement_flag);

      libmesh_assert (!level || elem->parent() != NULL);
      libmesh_assert (!level || elem->parent()->id() == parent_id);
      libmesh_assert (!level || elem->parent()->child(which_child_am_i) == elem);
#endif

      // Our neighbor links should be "close to" correct - we may have
      // to update them, but we can check for some inconsistencies.
      for (unsigned int n=0; n != elem->n_neighbors(); ++n)
        {
          const unsigned int neighbor_id =
            static_cast<unsigned int>(*in++);

	  // If the sending processor sees a domain boundary here,
	  // we'd better agree.
          if (neighbor_id == DofObject::invalid_id)
            {
              libmesh_assert(elem->neighbor(n) == NULL);
              continue;
            }

	  // If the sending processor has a remote_elem neighbor here,
	  // then all we know is that we'd better *not* have a domain
	  // boundary.
          if (neighbor_id == remote_elem->id())
            {
              libmesh_assert(elem->neighbor(n) != NULL);
              continue;
            }

          Elem *neigh = mesh->query_elem(neighbor_id);

          // The sending processor sees a neighbor here, so if we
          // don't have that neighboring element, then we'd better
          // have a remote_elem signifying that fact.
          if (!neigh)
            {
              libmesh_assert(elem->neighbor(n) == remote_elem);
              continue;
            }

          // The sending processor has a neighbor here, and we have
          // that element, but that does *NOT* mean we're already
	  // linking to it.  Perhaps we initially received both elem
	  // and neigh from processors on which their mutual link was
	  // remote?
          libmesh_assert(elem->neighbor(n) == neigh ||
			 elem->neighbor(n) == remote_elem);

	  // If the link was originally remote, we should update it,
	  // and make sure the appropriate parts of its family link
	  // back to us.
	  if (elem->neighbor(n) == remote_elem)
            {
              elem->set_neighbor(n, neigh); 

              elem->make_links_to_me_local(n); 
	    }
	}

      // FIXME: We should add some debug mode tests to ensure that the
      // encoded indexing and boundary conditions are consistent.
    }
  else
    {
      // We don't already have the element, so we need to create it.

      // Find the parent if necessary
      Elem *parent = NULL;
#ifdef LIBMESH_ENABLE_AMR
      // Find a child element's parent
      if (level > 0)
        {
	  // Note that we must be very careful to construct the send
	  // connectivity so that parents are encountered before
	  // children.  If we get here and can't find the parent that
	  // is a fatal error.
          parent = mesh->elem(parent_id);
        }
      // Or assert that the sending processor sees no parent
      else
        libmesh_assert (parent_id == static_cast<unsigned int>(-1));
#else
      // No non-level-0 elements without AMR
      libmesh_assert (level == 0);
#endif

      elem = Elem::build(type,parent).release();
      libmesh_assert (elem);

#ifdef LIBMESH_ENABLE_AMR
      if (level != 0)
        {
          // Since this is a newly created element, the parent must
          // have previously thought of this child as a remote element.
          libmesh_assert (parent->child(which_child_am_i) == remote_elem);

          parent->add_child(elem, which_child_am_i);
        }

      // Assign the refinement flags and levels
      elem->set_p_level(p_level);
      elem->set_refinement_flag(refinement_flag);
      elem->set_p_refinement_flag(p_refinement_flag);
      libmesh_assert (elem->level() == level);

      // If this element definitely should have children, assign
      // remote_elem to all of them for now, for consistency.  Later
      // unpacked elements may overwrite that.
      if (!elem->active())
        for (unsigned int c=0; c != elem->n_children(); ++c)
          elem->add_child(const_cast<RemoteElem*>(remote_elem), c);

#endif // LIBMESH_ENABLE_AMR

      // Assign the IDs
      elem->subdomain_id() = subdomain_id;
      elem->processor_id() = processor_id;
      elem->set_id()       = id;

      // Assign the connectivity
      libmesh_assert (elem->n_nodes() == n_nodes);

      for (unsigned int n=0; n != n_nodes; n++)
        elem->set_node(n) =
          mesh->node_ptr
	    (static_cast<unsigned int>(*in++));

      for (unsigned int n=0; n<elem->n_neighbors(); n++)
        {
          const unsigned int neighbor_id =
            static_cast<unsigned int>(*in++);

          if (neighbor_id == DofObject::invalid_id)
	    continue;

          // We may be unpacking an element that was a ghost element on the
          // sender, in which case the element's neighbors may not all be
          // known by the packed element.  We'll have to set such
          // neighbors to remote_elem ourselves and wait for a later
          // packed element to give us better information.
          if (neighbor_id == remote_elem->id())
            {
              elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem));
	      continue;
	    }

          // If we don't have the neighbor element, then it's a
          // remote_elem until we get it.
          Elem *neigh = mesh->query_elem(neighbor_id);
          if (!neigh)
            {
              elem->set_neighbor(n, const_cast<RemoteElem*>(remote_elem));
	      continue;
	    }

          // If we have the neighbor element, then link to it, and
          // make sure the appropriate parts of its family link back
          // to us.
          elem->set_neighbor(n, neigh);

          elem->make_links_to_me_local(n);
        }

      elem->unpack_indexing(in);
    }

  in += elem->packed_indexing_size();

  // If this is a coarse element,
  // add any element side boundary condition ids
  if (level == 0)
    for (unsigned int s = 0; s != elem->n_sides(); ++s)
      {
        const int num_bcs = *in++;
        libmesh_assert (num_bcs >= 0);

        for(int bc_it=0; bc_it < num_bcs; bc_it++)
          mesh->boundary_info->add_side (elem, s, *in++);
      }

  // Return the new element
  *out = elem;
}
예제 #5
0
// The actual implementation of building elements.
void InfElemBuilder::build_inf_elem(const Point& origin,
                                    const bool x_sym,
                                    const bool y_sym,
                                    const bool z_sym,
                                    const bool be_verbose,
                                    std::set< std::pair<dof_id_type,
                                    unsigned int> >* inner_faces)
{
    if (be_verbose)
    {
#ifdef DEBUG
        libMesh::out << " Building Infinite Elements:" << std::endl;
        libMesh::out << "  updating element neighbor tables..." << std::endl;
#else
        libMesh::out << " Verbose mode disabled in non-debug mode." << std::endl;
#endif
    }


    // update element neighbors
    this->_mesh.find_neighbors();

    START_LOG("build_inf_elem()", "InfElemBuilder");

    // A set for storing element number, side number pairs.
    // pair.first == element number, pair.second == side number
    std::set< std::pair<dof_id_type,unsigned int> > faces;
    std::set< std::pair<dof_id_type,unsigned int> > ofaces;

    // A set for storing node numbers on the outer faces.
    std::set<dof_id_type> onodes;

    // The distance to the farthest point in the mesh from the origin
    Real max_r=0.;

    // The index of the farthest point in the mesh from the origin
    int max_r_node = -1;

#ifdef DEBUG
    if (be_verbose)
    {
        libMesh::out << "  collecting boundary sides";
        if (x_sym || y_sym || z_sym)
            libMesh::out << ", skipping sides in symmetry planes..." << std::endl;
        else
            libMesh::out << "..." << std::endl;
    }
#endif

    // Iterate through all elements and sides, collect indices of all active
    // boundary sides in the faces set. Skip sides which lie in symmetry planes.
    // Later, sides of the inner boundary will be sorted out.
    {
        MeshBase::element_iterator       it  = this->_mesh.active_elements_begin();
        const MeshBase::element_iterator end = this->_mesh.active_elements_end();

        for(; it != end; ++it)
        {
            Elem* elem = *it;

            for (unsigned int s=0; s<elem->n_neighbors(); s++)
            {
                // check if elem(e) is on the boundary
                if (elem->neighbor(s) == NULL)
                {
                    // note that it is safe to use the Elem::side() method,
                    // which gives a non-full-ordered element
                    AutoPtr<Elem> side(elem->build_side(s));

                    // bool flags for symmetry detection
                    bool sym_side=false;
                    bool on_x_sym=true;
                    bool on_y_sym=true;
                    bool on_z_sym=true;


                    // Loop over the nodes to check whether they are on the symmetry planes,
                    // and therefore sufficient to use a non-full-ordered side element
                    for(unsigned int n=0; n<side->n_nodes(); n++)
                    {
                        const Point dist_from_origin = this->_mesh.point(side->node(n)) - origin;

                        if(x_sym)
                            if( std::abs(dist_from_origin(0)) > 1.e-3 )
                                on_x_sym=false;

                        if(y_sym)
                            if( std::abs(dist_from_origin(1)) > 1.e-3 )
                                on_y_sym=false;

                        if(z_sym)
                            if( std::abs(dist_from_origin(2)) > 1.e-3 )
                                on_z_sym=false;

                        // 	      if(x_sym)
                        // 		if( std::abs(dist_from_origin(0)) > 1.e-6 )
                        // 		  on_x_sym=false;

                        // 	      if(y_sym)
                        // 		if( std::abs(dist_from_origin(1)) > 1.e-6 )
                        // 		  on_y_sym=false;

                        // 	      if(z_sym)
                        // 		if( std::abs(dist_from_origin(2)) > 1.e-6 )
                        // 		  on_z_sym=false;

                        //find the node most distant from origin

                        Real r = dist_from_origin.size();
                        if (r > max_r)
                        {
                            max_r = r;
                            max_r_node=side->node(n);
                        }

                    }

                    sym_side = (x_sym && on_x_sym) || (y_sym && on_y_sym) || (z_sym && on_z_sym);

                    if (!sym_side)
                        faces.insert( std::make_pair(elem->id(), s) );

                } // neighbor(s) == NULL
            } // sides
        } // elems
    }






    //  If a boundary side has one node on the outer boundary,
    //  all points of this side are on the outer boundary.
    //  Start with the node most distant from origin, which has
    //  to be on the outer boundary, then recursively find all
    //  sides and nodes connected to it. Found sides are moved
    //  from faces to ofaces, nodes are collected in onodes.
    //  Here, the search is done iteratively, because, depending on
    //  the mesh, a very high level of recursion might be necessary.
    if (max_r_node > 0)
        onodes.insert(max_r_node);


    {
        std::set< std::pair<dof_id_type,unsigned int> >::iterator face_it = faces.begin();
        unsigned int facesfound=0;
        while (face_it != faces.end()) {

            std::pair<dof_id_type, unsigned int> p;
            p = *face_it;

            // This has to be a full-ordered side element,
            // since we need the correct n_nodes,
            AutoPtr<Elem> side(this->_mesh.elem(p.first)->build_side(p.second));

            bool found=false;
            for(unsigned int sn=0; sn<side->n_nodes(); sn++)
                if(onodes.count(side->node(sn)))
                {
                    found=true;
                    break;
                }


            // If a new oface is found, include its nodes in onodes
            if(found)
            {
                for(unsigned int sn=0; sn<side->n_nodes(); sn++)
                    onodes.insert(side->node(sn));

                ofaces.insert(p);
                face_it++;			// iteration is done here
                faces.erase(p);

                facesfound++;
            }

            else
                face_it++;			// iteration is done here


            // If at least one new oface was found in this cycle,
            // do another search cycle.
            if(facesfound>0 && face_it == faces.end())
            {
                facesfound = 0;
                face_it    = faces.begin();
            }

        }
    }


#ifdef DEBUG
    if (be_verbose)
        libMesh::out << "  found "
                     << faces.size()
                     << " inner and "
                     << ofaces.size()
                     << " outer boundary faces"
                     << std::endl;
#endif

    // When the user provided a non-null pointer to
    // inner_faces, that implies he wants to have
    // this std::set.  For now, simply copy the data.
    if (inner_faces != NULL)
        *inner_faces = faces;

    // free memory, clear our local variable, no need
    // for it any more.
    faces.clear();


    // outer_nodes maps onodes to their duplicates
    std::map<dof_id_type, Node *> outer_nodes;

    // We may need to pick our own object ids in parallel
    dof_id_type old_max_node_id = _mesh.max_node_id();
    dof_id_type old_max_elem_id = _mesh.max_elem_id();

    // for each boundary node, add an outer_node with
    // double distance from origin.
    std::set<dof_id_type>::iterator on_it = onodes.begin();
    for( ; on_it != onodes.end(); ++on_it)
    {
        Point p = (Point(this->_mesh.point(*on_it)) * 2) - origin;
        if (_mesh.is_serial())
        {
            // Add with a default id in serial
            outer_nodes[*on_it]=this->_mesh.add_point(p);
        }
        else
        {
            // Pick a unique id in parallel
            Node &bnode = _mesh.node(*on_it);
            dof_id_type new_id = bnode.id() + old_max_node_id;
            outer_nodes[*on_it] =
                this->_mesh.add_point(p, new_id,
                                      bnode.processor_id());
        }
    }


#ifdef DEBUG
    // for verbose, remember n_elem
    dof_id_type n_conventional_elem = this->_mesh.n_elem();
#endif


    // build Elems based on boundary side type
    std::set< std::pair<dof_id_type,unsigned int> >::iterator face_it = ofaces.begin();
    for( ; face_it != ofaces.end(); ++face_it)
    {
        // Shortcut to the pair being iterated over
        std::pair<dof_id_type,unsigned int> p = *face_it;

        // build a full-ordered side element to get the base nodes
        AutoPtr<Elem> side(this->_mesh.elem(p.first)->build_side(p.second));

        // create cell depending on side type, assign nodes,
        // use braces to force scope.
        bool is_higher_order_elem = false;
        {
            Elem* el;
            switch(side->type())
            {
            // 3D infinite elements
            // TRIs
            case TRI3:
                el=new InfPrism6;
                break;

            case TRI6:
                el=new InfPrism12;
                is_higher_order_elem = true;
                break;

            // QUADs
            case QUAD4:
                el=new InfHex8;
                break;

            case QUAD8:
                el=new InfHex16;
                is_higher_order_elem = true;
                break;

            case QUAD9:
                el=new InfHex18;

                // the method of assigning nodes (which follows below)
                // omits in the case of QUAD9 the bubble node; therefore
                // we assign these first by hand here.
                el->set_node(16) = side->get_node(8);
                el->set_node(17) = outer_nodes[side->node(8)];
                is_higher_order_elem=true;
                break;

            // 2D infinite elements
            case EDGE2:
                el=new InfQuad4;
                break;

            case EDGE3:
                el=new InfQuad6;
                el->set_node(4) = side->get_node(2);
                break;

            // 1D infinite elements not supported
            default:
                libMesh::out << "InfElemBuilder::build_inf_elem(Point, bool, bool, bool, bool): "
                             << "invalid face element "
                             << std::endl;
                continue;
            }

            // In parallel, assign unique ids to the new element
            if (!_mesh.is_serial())
            {
                Elem *belem = _mesh.elem(p.first);
                el->processor_id() = belem->processor_id();
                // We'd better not have elements with more than 6 sides
                el->set_id (belem->id() * 6 + p.second + old_max_elem_id);
            }

            // assign vertices to the new infinite element
            const unsigned int n_base_vertices = side->n_vertices();
            for(unsigned int i=0; i<n_base_vertices; i++)
            {
                el->set_node(i                ) = side->get_node(i);
                el->set_node(i+n_base_vertices) = outer_nodes[side->node(i)];
            }


            // when this is a higher order element,
            // assign also the nodes in between
            if (is_higher_order_elem)
            {
                // n_safe_base_nodes is the number of nodes in \p side
                // that may be safely assigned using below for loop.
                // Actually, n_safe_base_nodes is _identical_ with el->n_vertices(),
                // since for QUAD9, the 9th node was already assigned above
                const unsigned int n_safe_base_nodes   = el->n_vertices();

                for(unsigned int i=n_base_vertices; i<n_safe_base_nodes; i++)
                {
                    el->set_node(i+n_base_vertices)   = side->get_node(i);
                    el->set_node(i+n_safe_base_nodes) = outer_nodes[side->node(i)];
                }
            }


            // add infinite element to mesh
            this->_mesh.add_elem(el);
        } // el goes out of scope
    } // for


#ifdef DEBUG
    _mesh.libmesh_assert_valid_parallel_ids();

    if (be_verbose)
        libMesh::out << "  added "
                     << this->_mesh.n_elem() - n_conventional_elem
                     << " infinite elements and "
                     << onodes.size()
                     << " nodes to the mesh"
                     << std::endl
                     << std::endl;
#endif

    STOP_LOG("build_inf_elem()", "InfElemBuilder");
}