@@ -54,10 +54,7 @@ void LaplaceMeshSmoother::smooth(unsigned int n_iterations)
5454 auto on_boundary = MeshTools ::find_boundary_nodes (_mesh );
5555
5656 // Also: don't smooth block boundary nodes
57- auto on_block_boundary = MeshTools ::find_block_boundary_nodes (_mesh );
58-
59- // Merge them
60- on_boundary .insert (on_block_boundary .begin (), on_block_boundary .end ());
57+ auto block_boundary_map = MeshTools ::build_block_boundary_node_map (_mesh );
6158
6259 // We can only update the nodes after all new positions were
6360 // determined. We store the new positions here
@@ -67,11 +64,11 @@ void LaplaceMeshSmoother::smooth(unsigned int n_iterations)
6764 {
6865 new_positions .resize (_mesh .max_node_id ());
6966
70- auto calculate_new_position = [this , & on_boundary , & new_positions ](const Node * node ) {
67+ auto calculate_new_position = [this , & new_positions ](const Node * node ) {
7168 // leave the boundary intact
7269 // Only relocate the nodes which are vertices of an element
7370 // All other entries of _graph (the secondary nodes) are empty
74- if (! on_boundary . count ( node -> id ()) && ( _graph [node -> id ()].size () > 0 ) )
71+ if (_graph [node -> id ()].size () > 0 )
7572 {
7673 Point avg_position (0. ,0. ,0. );
7774
@@ -100,16 +97,58 @@ void LaplaceMeshSmoother::smooth(unsigned int n_iterations)
10097 _mesh .pid_nodes_end (DofObject ::invalid_processor_id )))
10198 calculate_new_position (node );
10299
100+ // update node position
101+ auto update_node_position = [this , & new_positions , & block_boundary_map , & on_boundary ](Node * node )
102+ {
103+ if (_graph [node -> id ()].size () == 0 )
104+ return ;
105+
106+ if (on_boundary .count (node -> id ()))
107+ {
108+ // project to boundary
109+ return ;
110+ }
111+
112+ // check if a node is on a given block boundary
113+ auto is_node_on_block_boundary = [& block_boundary_map ](dof_id_type node_id , const std ::pair < subdomain_id_type , subdomain_id_type > & block_boundary )
114+ {
115+ auto range = block_boundary_map .equal_range (node_id );
116+ for (auto i = range .first ; i != range .second ; ++ i )
117+ if (i -> second == block_boundary )
118+ return true;
119+ return false;
120+ };
121+
122+ const auto range = block_boundary_map .equal_range (node -> id ());
123+ const auto num_boundaries = std ::distance (range .first , range .second );
124+
125+ // do not touch nodes at the intersection of two or more boundaries
126+ if (num_boundaries > 1 )
127+ return ;
128+
129+ if (num_boundaries == 1 )
130+ {
131+ // project to block boundary
132+ const auto & boundary = range .first -> second ;
133+ // iterate over neighboring nodes that share the same boundary and check if all edges are coplanar/collinear
134+ for (const auto & connected_id : _graph [node -> id ()])
135+ if (is_node_on_block_boundary (connected_id , boundary ))
136+ continue ;
137+
138+ return ;
139+ }
140+
141+ // otherwise just move the node freely
142+ * node = new_positions [node -> id ()];
143+ };
103144
104145 // now update the node positions (local and unpartitioned nodes only)
105146 for (auto & node : _mesh .local_node_ptr_range ())
106- if (!on_boundary .count (node -> id ()) && (_graph [node -> id ()].size () > 0 ))
107- * node = new_positions [node -> id ()];
147+ update_node_position (node );
108148
109149 for (auto & node : as_range (_mesh .pid_nodes_begin (DofObject ::invalid_processor_id ),
110150 _mesh .pid_nodes_end (DofObject ::invalid_processor_id )))
111- if (!on_boundary .count (node -> id ()) && (_graph [node -> id ()].size () > 0 ))
112- * node = new_positions [node -> id ()];
151+ update_node_position (node );
113152
114153 // Now the nodes which are ghosts on this processor may have been moved on
115154 // the processors which own them. So we need to synchronize with our neighbors
0 commit comments