Пример #1
0
void
FeatureFloodCount::appendPeriodicNeighborNodes(FeatureData & data) const
{
  if (_is_elemental)
  {
    for (auto entity : data._local_ids)
    {
      Elem * elem = _mesh.elemPtr(entity);

      for (unsigned int node_n = 0; node_n < elem->n_nodes(); node_n++)
      {
        auto iters = _periodic_node_map.equal_range(elem->node(node_n));

        for (auto it = iters.first; it != iters.second; ++it)
        {
          data._periodic_nodes.insert(it->first);
          data._periodic_nodes.insert(it->second);
        }
      }
    }
  }
  else
  {
    for (auto entity : data._local_ids)
    {
      auto iters = _periodic_node_map.equal_range(entity);

      for (auto it = iters.first; it != iters.second; ++it)
      {
        data._periodic_nodes.insert(it->first);
        data._periodic_nodes.insert(it->second);
      }
    }
  }
}
Пример #2
0
void
GrainTracker::calculateBubbleVolumes()
{
  Moose::perf_log.push("calculateBubbleVolumes()", "GrainTracker");

  // The size of the bubble array will be sized to the max index of the unique grains map
  unsigned int max_id = _unique_grains.size() ? _unique_grains.rbegin()->first + 1: 0;
  _all_feature_volumes.resize(max_id, 0);

  const MeshBase::const_element_iterator el_end = _mesh.getMesh().active_local_elements_end();
  for (MeshBase::const_element_iterator el = _mesh.getMesh().active_local_elements_begin(); el != el_end; ++el)
  {
    Elem * elem = *el;
    unsigned int elem_n_nodes = elem->n_nodes();
    Real curr_volume = elem->volume();

    for (std::map<unsigned int, MooseSharedPointer<FeatureData> >::iterator it = _unique_grains.begin(); it != _unique_grains.end(); ++it)
    {
      if (it->second->_status == INACTIVE)
        continue;

      if (_is_elemental)
      {
        dof_id_type elem_id = elem->id();
        if (it->second->_local_ids.find(elem_id) != it->second->_local_ids.end())
        {
          mooseAssert(it->first < _all_feature_volumes.size(), "_all_feature_volumes access out of bounds");
          _all_feature_volumes[it->first] += curr_volume;
          break;
        }
      }
      else
      {
        // Count the number of nodes on this element which are flooded.
        unsigned int flooded_nodes = 0;
        for (unsigned int node = 0; node < elem_n_nodes; ++node)
        {
          dof_id_type node_id = elem->node(node);
          if (it->second->_local_ids.find(node_id) != it->second->_local_ids.end())
            ++flooded_nodes;
        }

        // If a majority of the nodes for this element are flooded,
        // assign its volume to the current bubble_counter entry.
        if (flooded_nodes >= elem_n_nodes / 2)
          _all_feature_volumes[it->first] += curr_volume;
      }
    }
  }

  // do all the sums!
  _communicator.sum(_all_feature_volumes);

  Moose::perf_log.pop("calculateBubbleVolumes()", "GrainTracker");
}
Пример #3
0
void
NodalFloodCount::calculateBubbleVolumes()
{
  Moose::perf_log.push("calculateBubbleVolume()", "NodalFloodCount");

  // Size our temporary data structure
  std::vector<std::vector<Real> > bubble_volumes(_maps_size);
  for (unsigned int map_num = 0; map_num < _maps_size; ++map_num)
  {
    bubble_volumes[map_num].resize(_bubble_sets[map_num].size());
  }

  std::vector<unsigned int> flood_nodes(_maps_size);
  const MeshBase::const_element_iterator el_end = _mesh.getMesh().active_local_elements_end();
  for (MeshBase::const_element_iterator el = _mesh.getMesh().active_local_elements_begin(); el != el_end; ++el)
  {
    Elem *elem = *el;
    unsigned int elem_n_nodes = elem->n_nodes();
    Real curr_volume = elem->volume();

    for (unsigned int map_num = 0; map_num < _maps_size; ++map_num)
    {
      unsigned int bubble_counter = 0;
      std::list<BubbleData>::const_iterator end = _bubble_sets[map_num].end();
      for (std::list<BubbleData>::const_iterator bubble_it1 = _bubble_sets[map_num].begin(); bubble_it1 != end; ++bubble_it1)
      {
        unsigned int flooded_nodes = 0;
        for (unsigned int node = 0; node < elem_n_nodes; ++node)
        {
          unsigned int node_id = elem->node(node);
          if (bubble_it1->_nodes.find(node_id) != bubble_it1->_nodes.end())
            ++flooded_nodes;
        }

        // Are a majority of the nodes flooded for this element?
        if (flooded_nodes >= elem_n_nodes / 2)
          bubble_volumes[map_num][bubble_counter] += curr_volume;

        ++bubble_counter;
      }
    }
  }

  // Stick all the partial bubble volumes in one long single vector to be gathered on the root processor
  for (unsigned int map_num = 0; map_num < _maps_size; ++map_num)
    _all_bubble_volumes.insert(_all_bubble_volumes.end(), bubble_volumes[map_num].begin(), bubble_volumes[map_num].end());

  _communicator.sum(_all_bubble_volumes); //do all the sums!

  std::sort(_all_bubble_volumes.begin(), _all_bubble_volumes.end(), std::greater<Real>());

  Moose::perf_log.pop("calculateBubbleVolume()", "NodalFloodCount");
}
Пример #4
0
void
FeatureFloodCount::appendPeriodicNeighborNodes(BubbleData & data) const
{
  // Using a typedef makes the code easier to understand and avoids repeating information.
  typedef std::multimap<dof_id_type, dof_id_type>::const_iterator IterType;

  if (_is_elemental)
  {
    for (std::set<dof_id_type>::iterator entity_it = data._entity_ids.begin(); entity_it != data._entity_ids.end(); ++entity_it)
    {
      Elem * elem = _mesh.elem(*entity_it);

      for (unsigned int node_n = 0; node_n < elem->n_nodes(); node_n++)
      {
        std::pair<IterType, IterType> iters = _periodic_node_map.equal_range(elem->node(node_n));

        for (IterType it = iters.first; it != iters.second; ++it)
        {
          data._periodic_nodes.insert(it->first);
          data._periodic_nodes.insert(it->second);
        }
      }
    }
  }
  else
  {
    for (std::set<dof_id_type>::iterator entity_it = data._entity_ids.begin(); entity_it != data._entity_ids.end(); ++entity_it)
    {
      std::pair<IterType, IterType> iters = _periodic_node_map.equal_range(*entity_it);

      for (IterType it = iters.first; it != iters.second; ++it)
      {
        data._periodic_nodes.insert(it->first);
        data._periodic_nodes.insert(it->second);
      }
    }
  }
}
Пример #5
0
void TetGenMeshInterface::triangulate_conformingDelaunayMesh_carvehole  (const std::vector<Point>& holes,
                                                                         double quality_constraint,
                                                                         double volume_constraint)
{
  // Before calling this function, the Mesh must contain a convex hull
  // of TRI3 elements which define the boundary.
  unsigned hull_integrity_check = check_hull_integrity();

  // Possibly die if hull integrity check failed
  this->process_hull_integrity_result(hull_integrity_check);

  // class tetgen_wrapper allows library access on a basic level
  TetGenWrapper tetgen_wrapper;

  // Copy Mesh's node points into TetGen data structure
  this->fill_pointlist(tetgen_wrapper);

  // >>> fill input structure "tetgenio" with facet data:
  int facet_num = this->_mesh.n_elem();

  // allocate memory in "tetgenio" structure:
  tetgen_wrapper.allocate_facetlist(facet_num, holes.size());


  // Set up tetgen data structures with existing facet information
  // from the convex hull.
  {
    int insertnum = 0;
    MeshBase::element_iterator it        = this->_mesh.elements_begin();
    const MeshBase::element_iterator end = this->_mesh.elements_end();
    for (; it != end ; ++it)
      {
        tetgen_wrapper.allocate_facet_polygonlist(insertnum, 1);
        tetgen_wrapper.allocate_polygon_vertexlist(insertnum, 0, 3);

        Elem* elem = *it;

        for (unsigned int j=0; j<elem->n_nodes(); ++j)
          {
            // We need to get the sequential index of elem->get_node(j), but
            // it should already be stored in _sequential_to_libmesh_node_map...
            unsigned libmesh_node_id = elem->node(j);

            // The libmesh node IDs may not be sequential, but can we assume
            // they are at least in order???  We will do so here.
            std::vector<unsigned>::iterator node_iter =
              Utility::binary_find(_sequential_to_libmesh_node_map.begin(),
                                   _sequential_to_libmesh_node_map.end(),
                                   libmesh_node_id);

            // Check to see if not found: this could also indicate the sequential
            // node map is not sorted...
            if (node_iter == _sequential_to_libmesh_node_map.end())
              {
                libMesh::err << "Global node " << libmesh_node_id << " not found in sequential node map!"  << std::endl;
                libmesh_error();
              }

            std::vector<unsigned>::difference_type
              sequential_index = std::distance(_sequential_to_libmesh_node_map.begin(), node_iter);

            // Debugging:
            //    libMesh::out << "libmesh_node_id=" << libmesh_node_id
            //         << ", sequential_index=" << sequential_index
            //         << std::endl;

            tetgen_wrapper.set_vertex(insertnum, // facet number
                                      0,         // polygon (always 0)
                                      j,         // local vertex index in tetgen input
                                      sequential_index);
          }

        // Go to next facet in polygonlist
        insertnum++;
      }
  }



  // fill hole list (if there are holes):
  if (holes.size() > 0)
    {
      std::vector<Point>::const_iterator ihole;
      unsigned hole_index = 0;
      for (ihole=holes.begin(); ihole!=holes.end(); ++ihole)
        tetgen_wrapper.set_hole(hole_index++, (*ihole)(0), (*ihole)(1), (*ihole)(2));
    }


  // Run TetGen triangulation method:
  // p = tetrahedralizes a piecewise linear complex (see definition in user manual)
  // Q = quiet, no terminal output
  // q = specify a minimum radius/edge ratio
  // a = tetrahedron volume constraint

  // assemble switches:
  std::ostringstream oss; // string holding switches
  oss << "pQ";

  if (quality_constraint != 0)
    oss << "q" << std::fixed << quality_constraint;

  if (volume_constraint != 0)
    oss << "a" << std::fixed << volume_constraint;

  std::string params = oss.str();

  tetgen_wrapper.set_switches(params); // TetGen switches: Piecewise linear complex, Quiet mode
  tetgen_wrapper.run_tetgen();

  // => nodes:
  unsigned int old_nodesnum = this->_mesh.n_nodes();
  REAL x=0., y=0., z=0.;
  const unsigned int num_nodes = tetgen_wrapper.get_numberofpoints();

  // Debugging:
  // libMesh::out << "Original mesh had " << old_nodesnum << " nodes." << std::endl;
  // libMesh::out << "Reserving space for " << num_nodes << " total nodes." << std::endl;

  // Reserve space for additional nodes in the node map
  _sequential_to_libmesh_node_map.reserve(num_nodes);

  // Add additional nodes to the Mesh.
  // Original code had i<=num_nodes here (Note: the indexing is:
  // foo[3*i], [3*i+1], [3*i+2]) But according to the TetGen docs, "In
  // all cases, the first item in any array is stored starting at
  // index [0]."
  for (unsigned int i=old_nodesnum; i<num_nodes; i++)
    {
      // Fill in x, y, z values
      tetgen_wrapper.get_output_node(i, x,y,z);

      // Catch the node returned by add_point()... this will tell us the ID
      // assigned by the Mesh.
      Node* new_node = this->_mesh.add_point ( Point(x,y,z) );

      // Store this new ID in our sequential-to-libmesh node mapping array
      _sequential_to_libmesh_node_map.push_back( new_node->id() );
    }

  // Debugging:
  //  std::copy(_sequential_to_libmesh_node_map.begin(),
  //    _sequential_to_libmesh_node_map.end(),
  //    std::ostream_iterator<unsigned>(std::cout, " "));
  //  std::cout << std::endl;


  // => tetrahedra:
  const unsigned int num_elements = tetgen_wrapper.get_numberoftetrahedra();

  // Vector that temporarily holds the node labels defining element connectivity.
  unsigned int node_labels[4];

  for (unsigned int i=0; i<num_elements; i++)
    {
      // TetGen only supports Tet4 elements.
      Elem* elem = new Tet4;

      // Fill up the the node_labels vector
      for (unsigned int j=0; j<elem->n_nodes(); j++)
        node_labels[j] = tetgen_wrapper.get_element_node(i,j);

      // Associate nodes with this element
      this->assign_nodes_to_elem(node_labels, elem);

      // Finally, add this element to the mesh
      this->_mesh.add_elem(elem);
    }

  // Delete original convex hull elements.  Is there ever a case where
  // we should not do this?
  this->delete_2D_hull_elements();
}
Пример #6
0
void SerialMesh::renumber_nodes_and_elements ()
{

  START_LOG("renumber_nodes_and_elem()", "Mesh");

  // node and element id counters
  unsigned int next_free_elem = 0;
  unsigned int next_free_node = 0;

  // Will hold the set of nodes that are currently connected to elements
  LIBMESH_BEST_UNORDERED_SET<Node*> connected_nodes;

  // Loop over the elements.  Note that there may
  // be NULLs in the _elements vector from the coarsening
  // process.  Pack the elements in to a contiguous array
  // and then trim any excess.
  {
    std::vector<Elem*>::iterator in        = _elements.begin();
    std::vector<Elem*>::iterator out       = _elements.begin();
    const std::vector<Elem*>::iterator end = _elements.end();

    for (; in != end; ++in)
      if (*in != NULL)
	{
	  Elem* elem = *in;

	  *out = *in;
	  ++out;

	  // Increment the element counter
	  elem->set_id (next_free_elem++);

          if(_skip_renumber_nodes_and_elements)
          {
            // Add this elements nodes to the connected list
            for (unsigned int n=0; n<elem->n_nodes(); n++)
              connected_nodes.insert(elem->get_node(n));
          }
          else  // We DO want node renumbering
          {
            // Loop over this element's nodes.  Number them,
            // if they have not been numbered already.  Also,
            // position them in the _nodes vector so that they
            // are packed contiguously from the beginning.
            for (unsigned int n=0; n<elem->n_nodes(); n++)
              if (elem->node(n) == next_free_node)     // don't need to process
                next_free_node++;                      // [(src == dst) below]
            
              else if (elem->node(n) > next_free_node) // need to process
	      {
		// The source and destination indices
		// for this node
		const unsigned int src_idx = elem->node(n);
		const unsigned int dst_idx = next_free_node++;
                
		// ensure we want to swap a valid nodes
		libmesh_assert (_nodes[src_idx] != NULL);
                
		// Swap the source and destination nodes
                std::swap(_nodes[src_idx],
                          _nodes[dst_idx] );
                
		// Set proper indices where that makes sense
		if (_nodes[src_idx] != NULL)
		  _nodes[src_idx]->set_id (src_idx);
		_nodes[dst_idx]->set_id (dst_idx);
	      }
          }
	}

    // Erase any additional storage. These elements have been
    // copied into NULL voids by the procedure above, and are
    // thus repeated and unnecessary.
    _elements.erase (out, end);
  }
  

  if(_skip_renumber_nodes_and_elements)
  {
    // Loop over the nodes.  Note that there may
    // be NULLs in the _nodes vector from the coarsening
    // process.  Pack the nodes in to a contiguous array
    // and then trim any excess.
    
    std::vector<Node*>::iterator in        = _nodes.begin();
    std::vector<Node*>::iterator out       = _nodes.begin();
    const std::vector<Node*>::iterator end = _nodes.end();

    for (; in != end; ++in)
      if (*in != NULL)
      {
        // This is a reference so that if we change the pointer it will change in the vector
        Node* & node = *in;
        
        // If this node is still connected to an elem, put it in the list
        if(connected_nodes.find(node) != connected_nodes.end())
        {
          *out = node;
          ++out;

          // Increment the node counter
          node->set_id (next_free_node++);
        }
        else // This node is orphaned, delete it!
        {
          this->boundary_info->remove (node);

          // delete the node
          delete node;
          node = NULL;
        }  
      }

    // Erase any additional storage.  Whatever was
    _nodes.erase (out, end);
  }
  else // We really DO want node renumbering
  {
    // Any nodes in the vector >= _nodes[next_free_node]
    // are not connected to any elements and may be deleted
    // if desired.

    // (This code block will erase the unused nodes)
    // Now, delete the unused nodes
    {
      std::vector<Node*>::iterator nd        = _nodes.begin();
      const std::vector<Node*>::iterator end = _nodes.end();

      std::advance (nd, next_free_node);

      for (std::vector<Node*>::iterator it=nd;
           it != end; ++it)
      {
        // Mesh modification code might have already deleted some
        // nodes
	if (*it == NULL)
          continue;

	// remove any boundary information associated with
	// this node
	this->boundary_info->remove (*it);

	// delete the node
	delete *it;
	*it = NULL;
      }

      _nodes.erase (nd, end);
    }
  }

  libmesh_assert (next_free_elem == _elements.size());
  libmesh_assert (next_free_node == _nodes.size());

  STOP_LOG("renumber_nodes_and_elem()", "Mesh");
}
Пример #7
0
void VTKIO::cells_to_vtk()
{
  const MeshBase& mesh = MeshOutput<MeshBase>::mesh();

  vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
  vtkSmartPointer<vtkIdList> pts = vtkSmartPointer<vtkIdList>::New();

  std::vector<int> types(mesh.n_active_local_elem());
  unsigned active_element_counter = 0;

  vtkSmartPointer<vtkIntArray> elem_id = vtkSmartPointer<vtkIntArray>::New();
  elem_id->SetName("libmesh_elem_id");
  elem_id->SetNumberOfComponents(1);

  vtkSmartPointer<vtkIntArray> subdomain_id = vtkSmartPointer<vtkIntArray>::New();
  subdomain_id->SetName("subdomain_id");
  subdomain_id->SetNumberOfComponents(1);

  MeshBase::const_element_iterator it = mesh.active_local_elements_begin();
  const MeshBase::const_element_iterator end = mesh.active_local_elements_end();
  for (; it != end; ++it, ++active_element_counter)
    {
      Elem *elem = *it;

      pts->SetNumberOfIds(elem->n_nodes());

      // get the connectivity for this element
      std::vector<dof_id_type> conn;
      elem->connectivity(0, VTK, conn);

      for (unsigned int i=0; i<conn.size(); ++i)
        {
          // If the node ID is not found in the _local_node_map, we'll
          // add it to the _vtk_grid.  NOTE[JWP]: none of the examples
          // I have actually enters this section of code...
          if (_local_node_map.find(conn[i]) == _local_node_map.end())
            {
              dof_id_type global_node_id = elem->node(i);

              const Node* the_node = mesh.node_ptr(global_node_id);

              // Error checking...
              if (the_node == NULL)
                {
                  libMesh::err << "Error getting pointer to node "
                               << global_node_id
                               << "!" << std::endl;
                  libmesh_error();
                }

              // InsertNextPoint accepts either a double or float array of length 3.
              Real pt[3] = {0., 0., 0.};
              for (unsigned int d=0; d<LIBMESH_DIM; ++d)
                pt[d] = (*the_node)(d);

              // Insert the point into the _vtk_grid
              vtkIdType local = _vtk_grid->GetPoints()->InsertNextPoint(pt);

              // Update the _local_node_map with the ID returned by VTK
              _local_node_map[global_node_id] = local;
            }

          // Otherwise, the node ID was found in the _local_node_map, so
          // insert it into the vtkIdList.
          pts->InsertId(i, _local_node_map[conn[i]]);
        }

      vtkIdType vtkcellid = cells->InsertNextCell(pts);
      types[active_element_counter] = this->get_elem_type(elem->type());
      elem_id->InsertTuple1(vtkcellid, elem->id());
      subdomain_id->InsertTuple1(vtkcellid, elem->subdomain_id());
    } // end loop over active elements

  _vtk_grid->SetCells(&types[0], cells);
  _vtk_grid->GetCellData()->AddArray(elem_id);
  _vtk_grid->GetCellData()->AddArray(subdomain_id);
}
Пример #8
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;
}
Пример #9
0
void
FeatureFloodCount::calculateBubbleVolumes()
{
  Moose::perf_log.push("calculateBubbleVolume()", "FeatureFloodCount");

  // Figure out which bubbles intersect the boundary if the user has enabled that capability.
  if (_compute_boundary_intersecting_volume)
  {
    // Create a std::set of node IDs which are on the boundary called all_boundary_node_ids.
    std::set<dof_id_type> all_boundary_node_ids;

    // Iterate over the boundary nodes, putting them into the std::set data structure
    MooseMesh::bnd_node_iterator
      boundary_nodes_it  = _mesh.bndNodesBegin(),
      boundary_nodes_end = _mesh.bndNodesEnd();
    for (; boundary_nodes_it != boundary_nodes_end; ++boundary_nodes_it)
    {
      BndNode * boundary_node = *boundary_nodes_it;
      all_boundary_node_ids.insert(boundary_node->_node->id());
    }

    // For each of the _maps_size BubbleData lists, determine if the set
    // of nodes includes any boundary nodes.
    for (unsigned int map_num = 0; map_num < _maps_size; ++map_num)
    {
      std::list<BubbleData>::iterator
        bubble_it = _bubble_sets[map_num].begin(),
        bubble_end = _bubble_sets[map_num].end();

      // Determine boundary intersection for each BubbleData object
      for (; bubble_it != bubble_end; ++bubble_it)
        bubble_it->_intersects_boundary = setsIntersect(all_boundary_node_ids.begin(), all_boundary_node_ids.end(),
                                                        bubble_it->_entity_ids.begin(), bubble_it->_entity_ids.end());
    }
  }

  // Size our temporary data structure
  std::vector<std::vector<Real> > bubble_volumes(_maps_size);
  for (unsigned int map_num = 0; map_num < _maps_size; ++map_num)
    bubble_volumes[map_num].resize(_bubble_sets[map_num].size());

  // Clear pre-existing values and allocate space to store the volume
  // of the boundary-intersecting grains for each variable.
  _total_volume_intersecting_boundary.clear();
  _total_volume_intersecting_boundary.resize(_maps_size);

  // Loop over the active local elements.  For each variable, and for
  // each BubbleData object, check whether a majority of the element's
  // nodes belong to that Bubble, and if so assign the element's full
  // volume to that bubble.
  const MeshBase::const_element_iterator el_end = _mesh.getMesh().active_local_elements_end();
  for (MeshBase::const_element_iterator el = _mesh.getMesh().active_local_elements_begin(); el != el_end; ++el)
  {
    Elem * elem = *el;
    unsigned int elem_n_nodes = elem->n_nodes();
    Real curr_volume = elem->volume();

    for (unsigned int map_num = 0; map_num < _maps_size; ++map_num)
    {
      std::list<BubbleData>::const_iterator
        bubble_it = _bubble_sets[map_num].begin(),
        bubble_end = _bubble_sets[map_num].end();

      for (unsigned int bubble_counter = 0; bubble_it != bubble_end; ++bubble_it, ++bubble_counter)
      {
        // Count the number of nodes on this element which are flooded.
        unsigned int flooded_nodes = 0;
        for (unsigned int node = 0; node < elem_n_nodes; ++node)
        {
          dof_id_type node_id = elem->node(node);
          if (bubble_it->_entity_ids.find(node_id) != bubble_it->_entity_ids.end())
            ++flooded_nodes;
        }

        // If a majority of the nodes for this element are flooded,
        // assign its volume to the current bubble_counter entry.
        if (flooded_nodes >= elem_n_nodes / 2)
        {
          bubble_volumes[map_num][bubble_counter] += curr_volume;

          // If the current bubble also intersects the boundary, also
          // accumlate the volume into the total volume of bubbles
          // which intersect the boundary.
          if (bubble_it->_intersects_boundary)
            _total_volume_intersecting_boundary[map_num] += curr_volume;
        }
      }
    }
  }

  // If we're calculating boundary-intersecting volumes, we have to normalize it by the
  // volume of the entire domain.
  if (_compute_boundary_intersecting_volume)
  {
    // Compute the total area using a bounding box.  FIXME: this
    // assumes the domain is rectangular and 2D, and is probably a
    // little expensive so we should only do it once if possible.
    MeshTools::BoundingBox bbox = MeshTools::bounding_box(_mesh);
    Real total_volume = (bbox.max()(0)-bbox.min()(0))*(bbox.max()(1)-bbox.min()(1));

    // Sum up the partial boundary grain volume contributions from all processors
    _communicator.sum(_total_volume_intersecting_boundary);

    // Scale the boundary intersecting grain volumes by the total domain volume
    for (unsigned int i = 0; i<_total_volume_intersecting_boundary.size(); ++i)
      _total_volume_intersecting_boundary[i] /= total_volume;
  }

  // Stick all the partial bubble volumes in one long single vector to be gathered on the root processor
  for (unsigned int map_num = 0; map_num < _maps_size; ++map_num)
    _all_bubble_volumes.insert(_all_bubble_volumes.end(), bubble_volumes[map_num].begin(), bubble_volumes[map_num].end());

  // do all the sums!
  _communicator.sum(_all_bubble_volumes);

  std::sort(_all_bubble_volumes.begin(), _all_bubble_volumes.end(), std::greater<Real>());

  Moose::perf_log.pop("calculateBubbleVolume()", "FeatureFloodCount");
}
//-----------------------------------------------------------------
// Mesh refinement methods
bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch)
{
  // This function must be run on all processors at once
  parallel_only();

  bool flags_changed = false;


  // Vector holding the maximum element level that touches a node.
  std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0);
  std::vector<unsigned char> max_p_level_at_node (_mesh.n_nodes(), 0);


  // Loop over all the active elements & fill the vector
  {
    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)
      {
	const Elem* elem = *elem_it;
	const unsigned char elem_level =
	  elem->level() + ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0);
	const unsigned char elem_p_level =
	  elem->p_level() + ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0);

	// Set the max_level at each node
	for (unsigned int n=0; n<elem->n_nodes(); n++)
	  {
	    const unsigned int node_number = elem->node(n);

	    libmesh_assert_less (node_number, max_level_at_node.size());

	    max_level_at_node[node_number] =
	      std::max (max_level_at_node[node_number], elem_level);
	    max_p_level_at_node[node_number] =
	      std::max (max_p_level_at_node[node_number], elem_p_level);
	  }
      }
  }


  // Now loop over the active elements and flag the elements
  // who violate the requested level mismatch
  {
    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;
	const unsigned int elem_level = elem->level();
	const unsigned int elem_p_level = elem->p_level();

	// Skip the element if it is already fully flagged
	if (elem->refinement_flag() == Elem::REFINE &&
            elem->p_refinement_flag() == Elem::REFINE)
	  continue;

	// Loop over the nodes, check for possible mismatch
	for (unsigned int n=0; n<elem->n_nodes(); n++)
	  {
	    const unsigned int node_number = elem->node(n);

	    // Flag the element for refinement if it violates
	    // the requested level mismatch
	    if ( (elem_level + max_mismatch) < max_level_at_node[node_number]
                 && elem->refinement_flag() != Elem::REFINE)
	      {
		elem->set_refinement_flag (Elem::REFINE);
		flags_changed = true;
	      }
	    if ( (elem_p_level + max_mismatch) < max_p_level_at_node[node_number]
                 && elem->p_refinement_flag() != Elem::REFINE)
	      {
		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;
}
Пример #11
0
void MeshBase::detect_interior_parents()
{
  // This requires an inspection on every processor
  parallel_object_only();

  // Check if the mesh contains mixed dimensions. If so, then set interior parents, otherwise return.
  if (this->elem_dimensions().size() == 1)
    return;

  //This map will be used to set interior parents
  LIBMESH_BEST_UNORDERED_MAP<dof_id_type, std::vector<dof_id_type> > node_to_elem;

  const_element_iterator el  = this->active_elements_begin();
  const_element_iterator end = this->active_elements_end();

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

      // Populating the node_to_elem map, same as MeshTools::build_nodes_to_elem_map
      for (unsigned int n=0; n<elem->n_vertices(); n++)
        {
          libmesh_assert_less (elem->id(), this->max_elem_id());

          node_to_elem[elem->node(n)].push_back(elem->id());
        }
    }

  // Automatically set interior parents
  el = this->elements_begin();
  for (; el!=end; ++el)
    {
      Elem * element = *el;

      // Ignore an 3D element or an element that already has an interior parent
      if (element->dim()>=LIBMESH_DIM || element->interior_parent())
        continue;

      // Start by generating a SET of elements that are dim+1 to the current
      // element at each vertex of the current element, thus ignoring interior nodes.
      // If one of the SET of elements is empty, then we will not have an interior parent
      // since an interior parent must be connected to all vertices of the current element
      std::vector< std::set<dof_id_type> > neighbors( element->n_vertices() );

      bool found_interior_parents = false;

      for (dof_id_type n=0; n < element->n_vertices(); n++)
        {
          std::vector<dof_id_type> & element_ids = node_to_elem[element->node(n)];
          for (std::vector<dof_id_type>::iterator e_it = element_ids.begin();
               e_it != element_ids.end(); e_it++)
            {
              dof_id_type eid = *e_it;
              if (this->elem(eid)->dim() == element->dim()+1)
                neighbors[n].insert(eid);
            }
          if (neighbors[n].size()>0)
            {
              found_interior_parents = true;
            }
          else
            {
              // We have found an empty set, no reason to continue
              // Ensure we set this flag to false before the break since it could have
              // been set to true for previous vertex
              found_interior_parents = false;
              break;
            }
        }

      // If we have successfully generated a set of elements for each vertex, we will compare
      // the set for vertex 0 will the sets for the vertices until we find a id that exists in
      // all sets.  If found, this is our an interior parent id.  The interior parent id found
      // will be the lowest element id if there is potential for multiple interior parents.
      if (found_interior_parents)
        {
          std::set<dof_id_type> & neighbors_0 = neighbors[0];
          for (std::set<dof_id_type>::iterator e_it = neighbors_0.begin();
               e_it != neighbors_0.end(); e_it++)
            {
              found_interior_parents=false;
              dof_id_type interior_parent_id = *e_it;
              for (dof_id_type n=1; n < element->n_vertices(); n++)
                {
                  if (neighbors[n].find(interior_parent_id)!=neighbors[n].end())
                    {
                      found_interior_parents=true;
                    }
                  else
                    {
                      found_interior_parents=false;
                      break;
                    }
                }
              if (found_interior_parents)
                {
                  element->set_interior_parent(this->elem(interior_parent_id));
                  break;
                }
            }
        }
    }
}
Пример #12
0
//-----------------------------------------------------------------
// Mesh refinement methods
bool MeshRefinement::limit_level_mismatch_at_node (const unsigned int max_mismatch)
{
  // This function must be run on all processors at once
  parallel_object_only();

  bool flags_changed = false;


  // Vector holding the maximum element level that touches a node.
  std::vector<unsigned char> max_level_at_node (_mesh.n_nodes(), 0);
  std::vector<unsigned char> max_p_level_at_node (_mesh.n_nodes(), 0);

  // Loop over all the active elements & fill the vector
  {
    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)
      {
        const Elem* elem = *elem_it;
        const unsigned char elem_level =
          cast_int<unsigned char>(elem->level() +
                                  ((elem->refinement_flag() == Elem::REFINE) ? 1 : 0));
        const unsigned char elem_p_level =
          cast_int<unsigned char>(elem->p_level() +
                                  ((elem->p_refinement_flag() == Elem::REFINE) ? 1 : 0));

        // Set the max_level at each node
        for (unsigned int n=0; n<elem->n_nodes(); n++)
          {
            const dof_id_type node_number = elem->node(n);

            libmesh_assert_less (node_number, max_level_at_node.size());

            max_level_at_node[node_number] =
              std::max (max_level_at_node[node_number], elem_level);
            max_p_level_at_node[node_number] =
              std::max (max_p_level_at_node[node_number], elem_p_level);
          }
      }
  }


  // Now loop over the active elements and flag the elements
  // who violate the requested level mismatch. Alternatively, if
  // _enforce_mismatch_limit_prior_to_refinement is true, swap refinement flags
  // accordingly.
  {
    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;
        const unsigned int elem_level = elem->level();
        const unsigned int elem_p_level = elem->p_level();

        // Skip the element if it is already fully flagged
        // unless we are enforcing mismatch prior to refienemnt and may need to
        // remove the refinement flag(s)
        if (elem->refinement_flag() == Elem::REFINE &&
            elem->p_refinement_flag() == Elem::REFINE
            && !_enforce_mismatch_limit_prior_to_refinement)
          continue;

        // Loop over the nodes, check for possible mismatch
        for (unsigned int n=0; n<elem->n_nodes(); n++)
          {
            const dof_id_type node_number = elem->node(n);

            // Flag the element for refinement if it violates
            // the requested level mismatch
            if ((elem_level + max_mismatch) < max_level_at_node[node_number]
                && elem->refinement_flag() != Elem::REFINE)
              {
                elem->set_refinement_flag (Elem::REFINE);
                flags_changed = true;
              }
            if ((elem_p_level + max_mismatch) < max_p_level_at_node[node_number]
                && elem->p_refinement_flag() != Elem::REFINE)
              {
                elem->set_p_refinement_flag (Elem::REFINE);
                flags_changed = true;
              }

            // Possibly enforce limit mismatch prior to refinement
            flags_changed |= this->enforce_mismatch_limit_prior_to_refinement(elem, POINT, max_mismatch);
          }
      }
  }

  // If flags changed on any processor then they changed globally
  this->comm().max(flags_changed);

  return flags_changed;
}