Example #1
0
void LaplaceMeshSmoother::init()
{
  switch (_mesh.mesh_dimension())
    {

      // TODO:[BSK] Fix this to work for refined meshes...  I think
      // the implementation was done quickly for Damien, who did not have
      // refined grids.  Fix it here and in the original Mesh member.

    case 2: // Stolen directly from build_L_graph in mesh_base.C
      {
        // Initialize space in the graph.  It is indexed by node id.
        // Each node may be connected to an arbitrary number of other
        // nodes via edges.
        _graph.resize(_mesh.max_node_id());

        MeshBase::element_iterator       el  = _mesh.active_local_elements_begin();
        const MeshBase::element_iterator end = _mesh.active_local_elements_end();

        for (; el != end; ++el)
          {
            // Constant handle for the element
            const Elem * elem = *el;

            for (unsigned int s=0; s<elem->n_neighbors(); s++)
              {
                // Only operate on sides which are on the
                // boundary or for which the current element's
                // id is greater than its neighbor's.
                // Sides get only built once.
                if ((elem->neighbor(s) == libmesh_nullptr) ||
                    (elem->id() > elem->neighbor(s)->id()))
                  {
                    UniquePtr<Elem> side(elem->build_side(s));
                    _graph[side->node_id(0)].push_back(side->node_id(1));
                    _graph[side->node_id(1)].push_back(side->node_id(0));
                  }
              }
          }
        _initialized = true;
        break;
      } // case 2

    case 3: // Stolen blatantly from build_L_graph in mesh_base.C
      {
        // Initialize space in the graph.
        _graph.resize(_mesh.max_node_id());

        MeshBase::element_iterator       el  = _mesh.active_local_elements_begin();
        const MeshBase::element_iterator end = _mesh.active_local_elements_end();

        for (; el != end; ++el)
          {
            // Shortcut notation for simplicity
            const Elem * elem = *el;

            for (unsigned int f=0; f<elem->n_neighbors(); f++) // Loop over faces
              if ((elem->neighbor(f) == libmesh_nullptr) ||
                  (elem->id() > elem->neighbor(f)->id()))
                {
                  // We need a full (i.e. non-proxy) element for the face, since we will
                  // be looking at its sides as well!
                  UniquePtr<Elem> face = elem->build_side(f, /*proxy=*/false);

                  for (unsigned int s=0; s<face->n_neighbors(); s++) // Loop over face's edges
                    {
                      // Here we can use a proxy
                      UniquePtr<Elem> side = face->build_side(s);

                      // At this point, we just insert the node numbers
                      // again.  At the end we'll call sort and unique
                      // to make sure there are no duplicates
                      _graph[side->node_id(0)].push_back(side->node_id(1));
                      _graph[side->node_id(1)].push_back(side->node_id(0));
                    }
                }
          }

        _initialized = true;
        break;
      } // case 3

    default:
      libmesh_error_msg("At this time it is not possible to smooth a dimension " << _mesh.mesh_dimension() << "mesh.  Aborting...");
    }

  // Done building graph from local elements.  Let's now allgather the
  // graph so that it is available on all processors for the actual
  // smoothing operation?
  this->allgather_graph();

  // In 3D, it's possible for > 2 processor partitions to meet
  // at a single edge, while in 2D only 2 processor partitions
  // share an edge.  Therefore the allgather'd graph in 3D may
  // now have duplicate entries and we need to remove them so
  // they don't foul up the averaging algorithm employed by the
  // Laplace smoother.
  for (unsigned i=0; i<_graph.size(); ++i)
    {
      // The std::unique algorithm removes duplicate *consecutive* elements from a range,
      // so it only makes sense to call it on a sorted range...
      std::sort(_graph[i].begin(), _graph[i].end());
      _graph[i].erase(std::unique(_graph[i].begin(), _graph[i].end()), _graph[i].end());
    }

} // init()