libMesh
Public Member Functions | List of all members
MeshSmootherTest Class Reference
Inheritance diagram for MeshSmootherTest:
[legend]

Public Member Functions

 LIBMESH_CPPUNIT_TEST_SUITE (MeshSmootherTest)
 The goal of this test is to verify proper operation of the MeshSmoother subclasses. More...
 
 CPPUNIT_TEST (testLaplaceQuad)
 
 CPPUNIT_TEST (testLaplaceTri)
 
 CPPUNIT_TEST (testVariationalQuad)
 
 CPPUNIT_TEST (testVariationalTri)
 
 CPPUNIT_TEST (testVariationalQuadMultipleSubdomains)
 
 CPPUNIT_TEST_SUITE_END ()
 
void setUp ()
 
void tearDown ()
 
void testSmoother (ReplicatedMesh &mesh, MeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false)
 
void testLaplaceQuad ()
 
void testLaplaceTri ()
 
void testVariationalQuad ()
 
void testVariationalTri ()
 
void testVariationalQuadMultipleSubdomains ()
 

Detailed Description

Definition at line 94 of file mesh_smoother_test.C.

Member Function Documentation

◆ CPPUNIT_TEST() [1/5]

MeshSmootherTest::CPPUNIT_TEST ( testLaplaceQuad  )

◆ CPPUNIT_TEST() [2/5]

MeshSmootherTest::CPPUNIT_TEST ( testLaplaceTri  )

◆ CPPUNIT_TEST() [3/5]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalQuad  )

◆ CPPUNIT_TEST() [4/5]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalTri  )

◆ CPPUNIT_TEST() [5/5]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalQuadMultipleSubdomains  )

◆ CPPUNIT_TEST_SUITE_END()

MeshSmootherTest::CPPUNIT_TEST_SUITE_END ( )

◆ LIBMESH_CPPUNIT_TEST_SUITE()

MeshSmootherTest::LIBMESH_CPPUNIT_TEST_SUITE ( MeshSmootherTest  )

The goal of this test is to verify proper operation of the MeshSmoother subclasses.

◆ setUp()

void MeshSmootherTest::setUp ( )
inline

Definition at line 116 of file mesh_smoother_test.C.

116 {}

◆ tearDown()

void MeshSmootherTest::tearDown ( )
inline

Definition at line 118 of file mesh_smoother_test.C.

118 {}

◆ testLaplaceQuad()

void MeshSmootherTest::testLaplaceQuad ( )
inline

Definition at line 279 of file mesh_smoother_test.C.

References mesh, libMesh::QUAD4, and TestCommWorld.

280  {
282  LaplaceMeshSmoother laplace(mesh);
283 
284  testSmoother(mesh, laplace, QUAD4);
285  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
MeshBase & mesh
This class defines the data structures necessary for Laplace smoothing.
void testSmoother(ReplicatedMesh &mesh, MeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false)

◆ testLaplaceTri()

void MeshSmootherTest::testLaplaceTri ( )
inline

Definition at line 288 of file mesh_smoother_test.C.

References mesh, TestCommWorld, and libMesh::TRI3.

289  {
291  LaplaceMeshSmoother laplace(mesh);
292 
293  testSmoother(mesh, laplace, TRI3);
294  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
MeshBase & mesh
This class defines the data structures necessary for Laplace smoothing.
void testSmoother(ReplicatedMesh &mesh, MeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false)

◆ testSmoother()

void MeshSmootherTest::testSmoother ( ReplicatedMesh mesh,
MeshSmoother smoother,
const ElemType  type,
const bool  multiple_subdomains = false 
)
inline

Definition at line 120 of file mesh_smoother_test.C.

References libMesh::MeshTools::Generation::build_square(), libMesh::MeshBase::get_boundary_info(), mesh, libMesh::Real, libMesh::MeshTools::Modification::redistribute(), libMesh::MeshSmoother::smooth(), libMesh::TOLERANCE, and libMesh::TRI3.

121  {
122  LOG_UNIT_TEST;
123 
124  unsigned int n_elems_per_side = 4;
125 
126  MeshTools::Generation::build_square(mesh, n_elems_per_side, n_elems_per_side,
127  0.,1.,0.,1., type);
128 
129  // Move it around so we have something that needs smoothing
130  DistortSquare ds;
132 
133  std::unordered_map<dof_id_type, Point> subdomain_boundary_node_id_to_point;
134  if (multiple_subdomains)
135  {
136  // Increment the subdomain id on the right half by 1
137  for (auto * elem : mesh.active_element_ptr_range())
138  if (elem->vertex_average()(0) > 0.5)
139  ++elem->subdomain_id();
140 
141  // This loop should NOT be combined with the one above because we need to
142  // finish checking and updating subdomain ids for all elements before
143  // recording the final subdomain boundary.
144  for (auto * elem : mesh.active_element_ptr_range())
145  for (const auto & s : elem->side_index_range())
146  {
147  const auto* neighbor = elem->neighbor_ptr(s);
148  if (neighbor == nullptr)
149  continue;
150 
151  if (elem->subdomain_id() != neighbor->subdomain_id())
152  // This side is part of a subdomain boundary, record the
153  // corresponding node locations
154  for (const auto & n : elem->nodes_on_side(s))
155  subdomain_boundary_node_id_to_point[elem->node_id(n)] = Point(*(elem->get_nodes()[n]));
156  }
157  }
158 
159  const auto & boundary_info = mesh.get_boundary_info();
160 
161  // Function to assert the distortion is as expected
162  auto center_distortion_is = [&boundary_info, n_elems_per_side]
163  (const Node & node, int d, bool distortion,
164  Real distortion_tol=TOLERANCE) {
165  const Real r = node(d);
166  const Real R = r * n_elems_per_side;
167  CPPUNIT_ASSERT_GREATER(-distortion_tol*distortion_tol, r);
168  CPPUNIT_ASSERT_GREATER(-distortion_tol*distortion_tol, 1-r);
169 
170  // If we're at the center we're fine
171  if (std::abs(r-0.5) < distortion_tol*distortion_tol)
172  return true;
173 
174  // Boundary nodes are allowed to slide along the boundary.
175  // However, nodes that are part of more than one boundary (i.e., corners) should remain fixed.
176 
177  // Get boundary ids associated with the node
178  std::vector<boundary_id_type> boundary_ids;
179  boundary_info.boundary_ids(&node, boundary_ids);
180 
181  switch (boundary_ids.size())
182  {
183  // Internal node
184  case 0:
185  return ((std::abs(R-std::round(R)) > distortion_tol) == distortion);
186  break;
187  // Sliding boundary node
188  case 1:
189  // Since sliding boundary nodes may or may not already be in the optimal
190  // position, they may or may not be different from the originally distorted
191  // mesh. Return true here to avoid issues.
192  return true;
193  break;
194  // Fixed boundary node, should not have moved
195  case 2:
196  if (std::abs(node(0)) < distortion_tol*distortion_tol ||
197  std::abs(node(0)-1) < distortion_tol*distortion_tol)
198  {
199  const Real R1 = node(1) * n_elems_per_side;
200  CPPUNIT_ASSERT_LESS(distortion_tol*distortion_tol, std::abs(R1-std::round(R1)));
201  return true;
202  }
203 
204  if (std::abs(node(1)) < distortion_tol*distortion_tol ||
205  std::abs(node(1)-1) < distortion_tol*distortion_tol)
206  {
207  const Real R0 = node(0) * n_elems_per_side;
208  CPPUNIT_ASSERT_LESS(distortion_tol*distortion_tol, std::abs(R0-std::round(R0)));
209 
210  return true;
211  }
212  return false;
213  break;
214  default:
215  libmesh_error_msg("Node has unsupported number of boundary ids = " << boundary_ids.size());
216  }
217  };
218 
219  // Function to check if a given node has changed based on previous mapping
220  auto is_internal_subdomain_boundary_node_the_same = [&subdomain_boundary_node_id_to_point]
221  (const Node & node) {
222  auto it = subdomain_boundary_node_id_to_point.find(node.id());
223  if (it != subdomain_boundary_node_id_to_point.end())
224  return (Point(node) == subdomain_boundary_node_id_to_point[node.id()]);
225  else
226  // node is not an internal subdomain boundary node, just return true
227  return true;
228  };
229 
230  // Make sure our DistortSquare transformation has distorted the mesh
231  for (auto node : mesh.node_ptr_range())
232  {
233  CPPUNIT_ASSERT(center_distortion_is(*node, 0, true));
234  CPPUNIT_ASSERT(center_distortion_is(*node, 1, true));
235  }
236 
237  // Transform the square mesh of triangles to a parallelogram mesh of triangles.
238  // This will allow the Variational Smoother to smooth the mesh to the optimal case
239  // of equilateral triangles
240  const bool is_variational_smoother_type = (dynamic_cast<VariationalMeshSmoother*>(&smoother) != nullptr);
241  if (type == TRI3 && is_variational_smoother_type)
242  {
243  SquareToParallelogram stp;
245  }
246 
247  // Enough iterations to mostly fix us up. Laplace seems to be at 1e-3
248  // tolerance by iteration 6, so hopefully everything is there on any
249  // system by 8.
250  const unsigned int num_iterations = is_variational_smoother_type ? 1 : 8;
251  for (unsigned int i=0; i != num_iterations; ++i)
252  smoother.smooth();
253 
254  // Transform the parallelogram mesh back to a square mesh. In the case of the
255  // Variational Smoother, equilateral triangular elements will be transformed
256  // into right triangular elements that align with the original undistorted mesh.
257  if (type == TRI3 && is_variational_smoother_type)
258  {
259  ParallelogramToSquare pts;
261  }
262 
263  // Make sure we're not too distorted anymore OR that interval subdomain boundary nodes did not change.
264  for (auto node : mesh.node_ptr_range())
265  {
266  if (multiple_subdomains)
267  {
268  CPPUNIT_ASSERT(is_internal_subdomain_boundary_node_the_same(*node));
269  }
270  else
271  {
272  CPPUNIT_ASSERT(center_distortion_is(*node, 0, false, 1e-3));
273  CPPUNIT_ASSERT(center_distortion_is(*node, 1, false, 1e-3));
274  }
275  }
276  }
A Node is like a Point, but with more information.
Definition: node.h:52
static constexpr Real TOLERANCE
MeshBase & mesh
void build_square(UnstructuredMesh &mesh, const unsigned int nx, const unsigned int ny, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 2D meshes.
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:165
virtual void smooth()=0
Function which actually performs the smoothing operations.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This is an implementation of Larisa Branets&#39; smoothing algorithms.
void redistribute(MeshBase &mesh, const FunctionBase< Real > &mapfunc)
Deterministically perturb the nodal locations.
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39

◆ testVariationalQuad()

void MeshSmootherTest::testVariationalQuad ( )
inline

Definition at line 298 of file mesh_smoother_test.C.

References mesh, libMesh::QUAD4, and TestCommWorld.

299  {
301  VariationalMeshSmoother variational(mesh);
302 
303  testSmoother(mesh, variational, QUAD4);
304  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
MeshBase & mesh
This is an implementation of Larisa Branets&#39; smoothing algorithms.
void testSmoother(ReplicatedMesh &mesh, MeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false)

◆ testVariationalQuadMultipleSubdomains()

void MeshSmootherTest::testVariationalQuadMultipleSubdomains ( )
inline

Definition at line 315 of file mesh_smoother_test.C.

References mesh, libMesh::QUAD4, and TestCommWorld.

316  {
318  VariationalMeshSmoother variational(mesh);
319 
320  testSmoother(mesh, variational, QUAD4, true);
321  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
MeshBase & mesh
This is an implementation of Larisa Branets&#39; smoothing algorithms.
void testSmoother(ReplicatedMesh &mesh, MeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false)

◆ testVariationalTri()

void MeshSmootherTest::testVariationalTri ( )
inline

Definition at line 307 of file mesh_smoother_test.C.

References mesh, TestCommWorld, and libMesh::TRI3.

308  {
310  VariationalMeshSmoother variational(mesh);
311 
312  testSmoother(mesh, variational, TRI3);
313  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
MeshBase & mesh
This is an implementation of Larisa Branets&#39; smoothing algorithms.
void testSmoother(ReplicatedMesh &mesh, MeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false)

The documentation for this class was generated from the following file: