24#include "libmesh/mesh_smoother_laplace.h"
25#include "libmesh/mesh_tools.h"
26#include "libmesh/elem.h"
27#include "libmesh/unstructured_mesh.h"
28#include "libmesh/parallel.h"
29#include "libmesh/parallel_ghost_sync.h"
30#include "libmesh/parallel_algebra.h"
31#include "libmesh/int_range.h"
32#include "libmesh/elem_side_builder.h"
33#include "libmesh/libmesh_logging.h"
39 const unsigned int n_iterations)
44 LOG_SCOPE(
"smooth()",
"LaplaceMeshSmoother");
58 on_boundary.insert(on_block_boundary.begin(), on_block_boundary.end());
62 std::vector<Point> new_positions;
68 auto calculate_new_position = [
this, &on_boundary, &new_positions](
const Node * node) {
72 if (!on_boundary.count(node->id()) && (
_graph[node->id()].size() > 0))
74 Point avg_position(0.,0.,0.);
76 for (
const auto & connected_id :
_graph[node->id()])
85 avg_position.
add( connected_node );
89 new_positions[node->id()] = avg_position /
static_cast<Real>(
_graph[node->id()].size());
94 for (
auto & node :
_mesh.local_node_ptr_range())
95 calculate_new_position(node);
99 calculate_new_position(node);
103 for (
auto & node :
_mesh.local_node_ptr_range())
104 if (!on_boundary.count(node->id()) && (
_graph[node->id()].size() > 0))
105 *node = new_positions[node->id()];
109 if (!on_boundary.count(node->id()) && (
_graph[node->id()].size() > 0))
110 *node = new_positions[node->id()];
124 for (
auto & elem :
_mesh.active_element_ptr_range())
128 const unsigned int son_begin = elem->n_vertices();
129 const unsigned int son_end = elem->n_nodes();
132 for (
unsigned int son=son_begin; son<son_end; son++)
135 if (!on_boundary.count(elem->node_id(son)))
137 const unsigned int n_adjacent_vertices =
138 elem->n_second_order_adjacent_vertices(son);
142 Point avg_position(0,0,0);
143 for (
unsigned int v=0; v<n_adjacent_vertices; v++)
145 _mesh.
point( elem->node_id( elem->second_order_adjacent_vertex(son,v) ) );
147 _mesh.
node_ref(elem->node_id(son)) = avg_position / n_adjacent_vertices;
153#ifdef LIBMESH_ENABLE_DEPRECATED
156 libmesh_deprecated();
183 [
this, &side_builder](
const Elem & elem) {
184 for (
auto s : elem.side_index_range())
190 if ((elem.neighbor_ptr(s) ==
nullptr) ||
191 (elem.id() > elem.neighbor_ptr(s)->id()))
193 const Elem & side = side_builder(elem, s);
200 for (
auto & elem :
_mesh.active_local_element_ptr_range())
201 elem_to_graph(*elem);
204 for (
auto & elem :
_mesh.active_unpartitioned_element_ptr_range())
205 elem_to_graph(*elem);
220 [
this, &side_builder, &face_builder](
const Elem & elem) {
221 for (
auto f : elem.side_index_range())
222 if ((elem.neighbor_ptr(f) ==
nullptr) ||
223 (elem.id() > elem.neighbor_ptr(f)->id()))
225 const Elem & face = face_builder(elem, f);
229 const Elem & side = side_builder(face, s);
240 for (
auto & elem :
_mesh.active_local_element_ptr_range())
241 elem_to_graph(*elem);
244 for (
auto & elem :
_mesh.active_unpartitioned_element_ptr_range())
245 elem_to_graph(*elem);
252 libmesh_error_msg(
"At this time it is not possible to smooth a dimension " <<
_mesh.
mesh_dimension() <<
"mesh. Aborting...");
266 for (
auto & id_vec :
_graph)
270 std::sort(id_vec.begin(), id_vec.end());
271 id_vec.erase(std::unique(id_vec.begin(), id_vec.end()), id_vec.end());
283 out_stream << i <<
": ";
284 std::copy(
_graph[i].begin(),
286 std::ostream_iterator<unsigned>(out_stream,
" "));
287 out_stream << std::endl;
301 std::vector<dof_id_type> flat_graph;
304 flat_graph.reserve(
_graph.size());
306 for (
const auto & id_vec :
_graph)
309 flat_graph.push_back (cast_int<dof_id_type>(id_vec.size()));
312 for (
const auto & dof : id_vec)
313 flat_graph.push_back(dof);
330 _graph.resize(max_node_id);
333 std::size_t cursor=0;
341 std::size_t n_entries = flat_graph[cursor++];
344 _graph[node_ctr].reserve(
_graph[node_ctr].size() + n_entries);
348 for (std::size_t i=0; i<n_entries; ++i)
349 _graph[node_ctr].push_back(flat_graph[cursor++]);
void allgather(const T &send_data, std::vector< T, A > &recv_data) const
static constexpr processor_id_type invalid_processor_id
An invalid processor_id to distinguish DoFs that have not been assigned to a processor.
Helper for building element sides that minimizes the construction of new elements.
This is the base class from which all geometric element types are derived.
dof_id_type node_id(const unsigned int i) const
IntRange< unsigned short > side_index_range() const
std::vector< std::vector< dof_id_type > > _graph
Data structure for holding the L-graph.
void print_graph(std::ostream &out_stream=libMesh::out) const
Mainly for debugging, this function will print out the connectivity graph which has been created.
bool _initialized
True if the L-graph has been created, false otherwise.
void init()
Initialization for the Laplace smoothing routine is basically identical to building an "L-graph" whic...
virtual void smooth() override
Redefinition of the smooth function from the base class.
LaplaceMeshSmoother(UnstructuredMesh &mesh, const unsigned int n_iterations)
Constructor.
unsigned int _n_iterations
Number of smoothing iterations to perform.
void allgather_graph()
This function allgather's the (local) graph after it is computed on each processor by the init() func...
virtual const Node & node_ref(const dof_id_type i) const
virtual const Point & point(const dof_id_type i) const =0
unsigned int mesh_dimension() const
virtual dof_id_type max_node_id() const =0
This class provides the necessary interface for mesh smoothing.
A Node is like a Point, but with more information.
processor_id_type processor_id() const
const Parallel::Communicator & comm() const
processor_id_type n_processors() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
void add(const TypeVector< T2 > &)
Add to this vector without creating a temporary.
The UnstructuredMesh class is derived from the MeshBase class.
void sync_dofobject_data_by_id(const Communicator &comm, const Iterator &range_begin, const Iterator &range_end, SyncFunctor &sync)
Request data about a range of ghost dofobjects uniquely identified by their id.
The libMesh namespace provides an interface to certain functionality in the library.
SimpleRange< IndexType > as_range(const std::pair< IndexType, IndexType > &p)
Helper function that allows us to treat a homogenous pair as a range.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
uint8_t processor_id_type
IntRange< T > make_range(T beg, T end)
The 2-parameter make_range() helper function returns an IntRange<T> when both input parameters are of...