@@ -54,10 +54,7 @@ void LaplaceMeshSmoother::smooth(unsigned int n_iterations)
54
54
auto on_boundary = MeshTools ::find_boundary_nodes (_mesh );
55
55
56
56
// 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 );
61
58
62
59
// We can only update the nodes after all new positions were
63
60
// determined. We store the new positions here
@@ -67,11 +64,11 @@ void LaplaceMeshSmoother::smooth(unsigned int n_iterations)
67
64
{
68
65
new_positions .resize (_mesh .max_node_id ());
69
66
70
- auto calculate_new_position = [this , & on_boundary , & new_positions ](const Node * node ) {
67
+ auto calculate_new_position = [this , & new_positions ](const Node * node ) {
71
68
// leave the boundary intact
72
69
// Only relocate the nodes which are vertices of an element
73
70
// 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 )
75
72
{
76
73
Point avg_position (0. ,0. ,0. );
77
74
@@ -100,16 +97,58 @@ void LaplaceMeshSmoother::smooth(unsigned int n_iterations)
100
97
_mesh .pid_nodes_end (DofObject ::invalid_processor_id )))
101
98
calculate_new_position (node );
102
99
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
+ };
103
144
104
145
// now update the node positions (local and unpartitioned nodes only)
105
146
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 );
108
148
109
149
for (auto & node : as_range (_mesh .pid_nodes_begin (DofObject ::invalid_processor_id ),
110
150
_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 );
113
152
114
153
// Now the nodes which are ghosts on this processor may have been moved on
115
154
// the processors which own them. So we need to synchronize with our neighbors
0 commit comments