unsigned TetGenMeshInterface::check_hull_integrity()
{
  // Check for easy return: if the Mesh is empty (i.e. if
  // somebody called triangulate_conformingDelaunayMesh on
  // a Mesh with no elements, then hull integrity check must
  // fail...
  if (_mesh.n_elem() == 0)
    return 3;

  MeshBase::element_iterator it        = this->_mesh.elements_begin();
  const MeshBase::element_iterator end = this->_mesh.elements_end();

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

      // Check for proper element type
      if (elem->type() != TRI3)
        {
          //libMesh::err << "ERROR: Some of the elements in the original mesh were not TRI3!" << std::endl;
          //libmesh_error();
          return 1;
        }

      for (unsigned int i=0; i<elem->n_neighbors(); ++i)
        {
          if (elem->neighbor(i) == NULL)
            {
              // libMesh::err << "ERROR: Non-convex hull, cannot be tetrahedralized." << std::endl;
              // libmesh_error();
              return 2;
            }
        }
    }

  // If we made it here, return success!
  return 0;
}
void UnstructuredMesh::find_neighbors (const bool reset_remote_elements,
                                       const bool reset_current_list)
{
  // We might actually want to run this on an empty mesh
  // (e.g. the boundary mesh for a nonexistant bcid!)
  // libmesh_assert_not_equal_to (this->n_nodes(), 0);
  // libmesh_assert_not_equal_to (this->n_elem(), 0);

  // This function must be run on all processors at once
  parallel_object_only();

  LOG_SCOPE("find_neighbors()", "Mesh");

  const element_iterator el_end = this->elements_end();

  //TODO:[BSK] This should be removed later?!
  if (reset_current_list)
    for (element_iterator el = this->elements_begin(); el != el_end; ++el)
      {
        Elem * e = *el;
        for (unsigned int s=0; s<e->n_neighbors(); s++)
          if (e->neighbor_ptr(s) != remote_elem ||
              reset_remote_elements)
            e->set_neighbor(s, libmesh_nullptr);
      }

  // Find neighboring elements by first finding elements
  // with identical side keys and then check to see if they
  // are neighbors
  {
    // data structures -- Use the hash_multimap if available
    typedef unsigned int                    key_type;
    typedef std::pair<Elem *, unsigned char> val_type;
    typedef std::pair<key_type, val_type>   key_val_pair;

    typedef LIBMESH_BEST_UNORDERED_MULTIMAP<key_type, val_type> map_type;

    // A map from side keys to corresponding elements & side numbers
    map_type side_to_elem_map;



    for (element_iterator el = this->elements_begin(); el != el_end; ++el)
      {
        Elem * element = *el;

        for (unsigned char ms=0; ms<element->n_neighbors(); ms++)
          {
          next_side:
            // If we haven't yet found a neighbor on this side, try.
            // Even if we think our neighbor is remote, that
            // information may be out of date.
            if (element->neighbor_ptr(ms) == libmesh_nullptr ||
                element->neighbor_ptr(ms) == remote_elem)
              {
                // Get the key for the side of this element
                const unsigned int key = element->key(ms);

                // Look for elements that have an identical side key
                std::pair <map_type::iterator, map_type::iterator>
                  bounds = side_to_elem_map.equal_range(key);

                // May be multiple keys, check all the possible
                // elements which _might_ be neighbors.
                if (bounds.first != bounds.second)
                  {
                    // Get the side for this element
                    const UniquePtr<Elem> my_side(element->side_ptr(ms));

                    // Look at all the entries with an equivalent key
                    while (bounds.first != bounds.second)
                      {
                        // Get the potential element
                        Elem * neighbor = bounds.first->second.first;

                        // Get the side for the neighboring element
                        const unsigned int ns = bounds.first->second.second;
                        const UniquePtr<Elem> their_side(neighbor->side_ptr(ns));
                        //libmesh_assert(my_side.get());
                        //libmesh_assert(their_side.get());

                        // If found a match with my side
                        //
                        // We need special tests here for 1D:
                        // since parents and children have an equal
                        // side (i.e. a node), we need to check
                        // ns != ms, and we also check level() to
                        // avoid setting our neighbor pointer to
                        // any of our neighbor's descendants
                        if( (*my_side == *their_side) &&
                            (element->level() == neighbor->level()) &&
                            ((element->dim() != 1) || (ns != ms)) )
                          {
                            // So share a side.  Is this a mixed pair
                            // of subactive and active/ancestor
                            // elements?
                            // If not, then we're neighbors.
                            // If so, then the subactive's neighbor is

                            if (element->subactive() ==
                                neighbor->subactive())
                              {
                                // an element is only subactive if it has
                                // been coarsened but not deleted
                                element->set_neighbor (ms,neighbor);
                                neighbor->set_neighbor(ns,element);
                              }
                            else if (element->subactive())
                              {
                                element->set_neighbor(ms,neighbor);
                              }
                            else if (neighbor->subactive())
                              {
                                neighbor->set_neighbor(ns,element);
                              }
                            side_to_elem_map.erase (bounds.first);

                            // get out of this nested crap
                            goto next_side;
                          }

                        ++bounds.first;
                      }
                  }

                // didn't find a match...
                // Build the map entry for this element
                key_val_pair kvp;

                kvp.first         = key;
                kvp.second.first  = element;
                kvp.second.second = ms;

                // use the lower bound as a hint for
                // where to put it.
#if defined(LIBMESH_HAVE_UNORDERED_MAP) || defined(LIBMESH_HAVE_TR1_UNORDERED_MAP) || defined(LIBMESH_HAVE_HASH_MAP) || defined(LIBMESH_HAVE_EXT_HASH_MAP)
                side_to_elem_map.insert (kvp);
#else
                side_to_elem_map.insert (bounds.first,kvp);
#endif
              }
          }
      }
  }

#ifdef LIBMESH_ENABLE_AMR

  /**
   * Here we look at all of the child elements which
   * don't already have valid neighbors.
   *
   * If a child element has a NULL neighbor it is
   * either because it is on the boundary or because
   * its neighbor is at a different level.  In the
   * latter case we must get the neighbor from the
   * parent.
   *
   * If a child element has a remote_elem neighbor
   * on a boundary it shares with its parent, that
   * info may have become out-dated through coarsening
   * of the neighbor's parent.  In this case, if the
   * parent's neighbor is active then the child should
   * share it.
   *
   * Furthermore, that neighbor better be active,
   * otherwise we missed a child somewhere.
   *
   *
   * We also need to look through children ordered by increasing
   * refinement level in order to add new interior_parent() links in
   * boundary elements which have just been generated by refinement,
   * and fix links in boundary elements whose previous
   * interior_parent() has just been coarsened away.
   */
  const unsigned int n_levels = MeshTools::n_levels(*this);
  for (unsigned int level = 1; level < n_levels; ++level)
    {
      element_iterator end = this->level_elements_end(level);
      for (element_iterator el = this->level_elements_begin(level);
           el != end; ++el)
        {
          Elem * current_elem = *el;
          libmesh_assert(current_elem);
          Elem * parent = current_elem->parent();
          libmesh_assert(parent);
          const unsigned int my_child_num = parent->which_child_am_i(current_elem);

          for (unsigned int s=0; s < current_elem->n_neighbors(); s++)
            {
              if (current_elem->neighbor_ptr(s) == libmesh_nullptr ||
                  (current_elem->neighbor_ptr(s) == remote_elem &&
                   parent->is_child_on_side(my_child_num, s)))
                {
                  Elem * neigh = parent->neighbor_ptr(s);

                  // If neigh was refined and had non-subactive children
                  // made remote earlier, then a non-subactive elem should
                  // actually have one of those remote children as a
                  // neighbor
                  if (neigh && (neigh->ancestor()) && (!current_elem->subactive()))
                    {
#ifdef DEBUG
                      // Let's make sure that "had children made remote"
                      // situation is actually the case
                      libmesh_assert(neigh->has_children());
                      bool neigh_has_remote_children = false;
                      for (unsigned int c = 0; c != neigh->n_children(); ++c)
                        {
                          if (neigh->child_ptr(c) == remote_elem)
                            neigh_has_remote_children = true;
                        }
                      libmesh_assert(neigh_has_remote_children);

                      // And let's double-check that we don't have
                      // a remote_elem neighboring a local element
                      libmesh_assert_not_equal_to (current_elem->processor_id(),
                                                   this->processor_id());
#endif // DEBUG
                      neigh = const_cast<RemoteElem *>(remote_elem);
                    }

                  if (!current_elem->subactive())
                    current_elem->set_neighbor(s, neigh);
#ifdef DEBUG
                  if (neigh != libmesh_nullptr && neigh != remote_elem)
                    // We ignore subactive elements here because
                    // we don't care about neighbors of subactive element.
                    if ((!neigh->active()) && (!current_elem->subactive()))
                      {
                        libMesh::err << "On processor " << this->processor_id()
                                     << std::endl;
                        libMesh::err << "Bad element ID = " << current_elem->id()
                                     << ", Side " << s << ", Bad neighbor ID = " << neigh->id() << std::endl;
                        libMesh::err << "Bad element proc_ID = " << current_elem->processor_id()
                                     << ", Bad neighbor proc_ID = " << neigh->processor_id() << std::endl;
                        libMesh::err << "Bad element size = " << current_elem->hmin()
                                     << ", Bad neighbor size = " << neigh->hmin() << std::endl;
                        libMesh::err << "Bad element center = " << current_elem->centroid()
                                     << ", Bad neighbor center = " << neigh->centroid() << std::endl;
                        libMesh::err << "ERROR: "
                                     << (current_elem->active()?"Active":"Ancestor")
                                     << " Element at level "
                                     << current_elem->level() << std::endl;
                        libMesh::err << "with "
                                     << (parent->active()?"active":
                                         (parent->subactive()?"subactive":"ancestor"))
                                     << " parent share "
                                     << (neigh->subactive()?"subactive":"ancestor")
                                     << " neighbor at level " << neigh->level()
                                     << std::endl;
                        NameBasedIO(*this).write ("bad_mesh.gmv");
                        libmesh_error_msg("Problematic mesh written to bad_mesh.gmv.");
                      }
#endif // DEBUG
                }
            }

          // We can skip to the next element if we're full-dimension
          // and therefore don't have any interior parents
          if (current_elem->dim() >= LIBMESH_DIM)
            continue;

          // We have no interior parents unless we can find one later
          current_elem->set_interior_parent(libmesh_nullptr);

          Elem * pip = parent->interior_parent();

          if (!pip)
            continue;

          // If there's no interior_parent children, whether due to a
          // remote element or a non-conformity, then there's no
          // children to search.
          if (pip == remote_elem || pip->active())
            {
              current_elem->set_interior_parent(pip);
              continue;
            }

          // For node comparisons we'll need a sensible tolerance
          Real node_tolerance = current_elem->hmin() * TOLERANCE;

          // Otherwise our interior_parent should be a child of our
          // parent's interior_parent.
          for (unsigned int c=0; c != pip->n_children(); ++c)
            {
              Elem * child = pip->child_ptr(c);

              // If we have a remote_elem, that might be our
              // interior_parent.  We'll set it provisionally now and
              // keep trying to find something better.
              if (child == remote_elem)
                {
                  current_elem->set_interior_parent
                    (const_cast<RemoteElem *>(remote_elem));
                  continue;
                }

              bool child_contains_our_nodes = true;
              for (unsigned int n=0; n != current_elem->n_nodes();
                   ++n)
                {
                  bool child_contains_this_node = false;
                  for (unsigned int cn=0; cn != child->n_nodes();
                       ++cn)
                    if (child->point(cn).absolute_fuzzy_equals
                        (current_elem->point(n), node_tolerance))
                      {
                        child_contains_this_node = true;
                        break;
                      }
                  if (!child_contains_this_node)
                    {
                      child_contains_our_nodes = false;
                      break;
                    }
                }
              if (child_contains_our_nodes)
                {
                  current_elem->set_interior_parent(child);
                  break;
                }
            }

          // We should have found *some* interior_parent at this
          // point, whether semilocal or remote.
          libmesh_assert(current_elem->interior_parent());
        }
    }

#endif // AMR


#ifdef DEBUG
  MeshTools::libmesh_assert_valid_neighbors(*this,
                                            !reset_remote_elements);
  MeshTools::libmesh_assert_valid_amr_interior_parents(*this);
#endif
}
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;
}
Beispiel #4
0
void unpack(std::vector<largest_id_type>::const_iterator in,
            Elem** out,
            MeshBase* mesh)
{
#ifndef NDEBUG
  const std::vector<largest_id_type>::const_iterator original_in = in;

  const largest_id_type incoming_header = *in++;
  libmesh_assert_equal_to (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_greater_equal (rflag, 0);
  libmesh_assert_less (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_greater_equal (pflag, 0);
  libmesh_assert_less (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_greater_equal (typeint, 0);
  libmesh_assert_less (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 processor_id_type processor_id =
    static_cast<processor_id_type>(*in++);
  libmesh_assert (processor_id < mesh->n_processors() ||
                  processor_id == DofObject::invalid_processor_id);

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

  // int 7: dof object id
  const dof_id_type id =
    static_cast<dof_id_type>(*in++);
  libmesh_assert_not_equal_to (id, DofObject::invalid_id);

#ifdef LIBMESH_ENABLE_UNIQUE_ID
  // int 8: dof object unique id
  const unique_id_type unique_id =
    static_cast<unique_id_type>(*in++);
#endif

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

  // int 10: 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_equal_to (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_equal_to (elem->level(), level);
      libmesh_assert_equal_to (elem->id(), id);
//#ifdef LIBMESH_ENABLE_UNIQUE_ID
      // No check for unqiue id sanity
//#endif
      libmesh_assert_equal_to (elem->processor_id(), processor_id);
      libmesh_assert_equal_to (elem->subdomain_id(), subdomain_id);
      libmesh_assert_equal_to (elem->type(), type);
      libmesh_assert_equal_to (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<dof_id_type>(*in++));
#else
      in += n_nodes;
#endif

#ifdef LIBMESH_ENABLE_AMR
      libmesh_assert_equal_to (elem->p_level(), p_level);
      libmesh_assert_equal_to (elem->refinement_flag(), refinement_flag);
      libmesh_assert_equal_to (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 dof_id_type neighbor_id =
            static_cast<dof_id_type>(*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)));
              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));
              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_equal_to (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_equal_to (parent_id, static_cast<dof_id_type>(-1));
#else
      // No non-level-0 elements without AMR
      libmesh_assert_equal_to (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_equal_to (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_equal_to (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;
#ifdef LIBMESH_ENABLE_UNIQUE_ID
      elem->set_unique_id() = unique_id;
#endif

      // Assign the connectivity
      libmesh_assert_equal_to (elem->n_nodes(), n_nodes);

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

      for (unsigned int n=0; n<elem->n_neighbors(); n++)
        {
          const dof_id_type neighbor_id =
            static_cast<dof_id_type>(*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_greater_equal (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;
}
Beispiel #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");
}