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 (testVariationalEdge2)
 
 CPPUNIT_TEST (testVariationalEdge3)
 
 CPPUNIT_TEST (testVariationalEdge3MultipleSubdomains)
 
 CPPUNIT_TEST (testVariationalQuad4)
 
 CPPUNIT_TEST (testVariationalQuad4MultipleSubdomains)
 
 CPPUNIT_TEST (testVariationalQuad8)
 
 CPPUNIT_TEST (testVariationalQuad9)
 
 CPPUNIT_TEST (testVariationalQuad9MultipleSubdomains)
 
 CPPUNIT_TEST (testVariationalQuad4Tangled)
 
 CPPUNIT_TEST (testVariationalTri3)
 
 CPPUNIT_TEST (testVariationalTri6)
 
 CPPUNIT_TEST (testVariationalTri6MultipleSubdomains)
 
 CPPUNIT_TEST (testVariationalHex8)
 
 CPPUNIT_TEST (testVariationalHex20)
 
 CPPUNIT_TEST (testVariationalHex27)
 
 CPPUNIT_TEST (testVariationalHex27Tangled)
 
 CPPUNIT_TEST (testVariationalHex27MultipleSubdomains)
 
 CPPUNIT_TEST (testVariationalPyramid5)
 
 CPPUNIT_TEST (testVariationalPyramid13)
 
 CPPUNIT_TEST (testVariationalPyramid14)
 
 CPPUNIT_TEST (testVariationalPyramid18)
 
 CPPUNIT_TEST (testVariationalPyramid18MultipleSubdomains)
 
 CPPUNIT_TEST (testVariationalPrism6)
 
 CPPUNIT_TEST (testVariationalPrism15)
 
 CPPUNIT_TEST (testVariationalPrism18)
 
 CPPUNIT_TEST (testVariationalPrism20)
 
 CPPUNIT_TEST (testVariationalPrism21)
 
 CPPUNIT_TEST (testVariationalPrism21MultipleSubdomains)
 
 CPPUNIT_TEST (testVariationalTet4)
 
 CPPUNIT_TEST (testVariationalTet10)
 
 CPPUNIT_TEST (testVariationalTet14)
 
 CPPUNIT_TEST (testVariationalTet14MultipleSubdomains)
 
 CPPUNIT_TEST (testVariationalMixed2D)
 
 CPPUNIT_TEST (testVariationalMixed3D)
 
 CPPUNIT_TEST_SUITE_END ()
 
void setUp ()
 
void tearDown ()
 
void testLaplaceSmoother (ReplicatedMesh &mesh, MeshSmoother &smoother, ElemType type)
 
std::pair< unsigned int, unsigned intnumCenteredAndFacedDimensions (const Point &point, const Real &side_length, const Real &tol)
 
bool pointIsCubeCenter (const Point &point, const Real &side_length, const Real &tol=TOLERANCE)
 
bool pointIsCubeVertex (const Point &point, const Real &side_length, const Real &tol=TOLERANCE)
 
bool pointIsCubeFaceCenter (const Point &point, const Real &side_length, const Real &tol=TOLERANCE)
 
void testVariationalSmoother (Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
 
void testVariationalSmootherRegression (const ReplicatedMesh &gold_mesh)
 
void testLaplaceQuad ()
 
void testLaplaceTri ()
 
void testVariationalEdge2 ()
 
void testVariationalEdge3 ()
 
void testVariationalEdge3MultipleSubdomains ()
 
void testVariationalQuad4 ()
 
void testVariationalQuad4MultipleSubdomains ()
 
void testVariationalQuad8 ()
 
void testVariationalQuad9 ()
 
void testVariationalQuad9MultipleSubdomains ()
 
void testVariationalQuad4Tangled ()
 
void testVariationalTri3 ()
 
void testVariationalTri6 ()
 
void testVariationalTri6MultipleSubdomains ()
 
void testVariationalHex8 ()
 
void testVariationalHex20 ()
 
void testVariationalHex27 ()
 
void testVariationalHex27MultipleSubdomains ()
 
void testVariationalHex27Tangled ()
 
void testVariationalPyramid5 ()
 
void testVariationalPyramid13 ()
 
void testVariationalPyramid14 ()
 
void testVariationalPyramid18 ()
 
void testVariationalPyramid18MultipleSubdomains ()
 
void testVariationalPrism6 ()
 
void testVariationalPrism15 ()
 
void testVariationalPrism18 ()
 
void testVariationalPrism20 ()
 
void testVariationalPrism21 ()
 
void testVariationalPrism21MultipleSubdomains ()
 
void testVariationalTet4 ()
 
void testVariationalTet10 ()
 
void testVariationalTet14 ()
 
void testVariationalTet14MultipleSubdomains ()
 
void testVariationalMixed2D ()
 
void testVariationalMixed3D ()
 

Detailed Description

Definition at line 221 of file mesh_smoother_test.C.

Member Function Documentation

◆ CPPUNIT_TEST() [1/36]

MeshSmootherTest::CPPUNIT_TEST ( testLaplaceQuad  )

◆ CPPUNIT_TEST() [2/36]

MeshSmootherTest::CPPUNIT_TEST ( testLaplaceTri  )

◆ CPPUNIT_TEST() [3/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalEdge2  )

◆ CPPUNIT_TEST() [4/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalEdge3  )

◆ CPPUNIT_TEST() [5/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalEdge3MultipleSubdomains  )

◆ CPPUNIT_TEST() [6/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalQuad4  )

◆ CPPUNIT_TEST() [7/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalQuad4MultipleSubdomains  )

◆ CPPUNIT_TEST() [8/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalQuad8  )

◆ CPPUNIT_TEST() [9/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalQuad9  )

◆ CPPUNIT_TEST() [10/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalQuad9MultipleSubdomains  )

◆ CPPUNIT_TEST() [11/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalQuad4Tangled  )

◆ CPPUNIT_TEST() [12/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalTri3  )

◆ CPPUNIT_TEST() [13/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalTri6  )

◆ CPPUNIT_TEST() [14/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalTri6MultipleSubdomains  )

◆ CPPUNIT_TEST() [15/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalHex8  )

◆ CPPUNIT_TEST() [16/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalHex20  )

◆ CPPUNIT_TEST() [17/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalHex27  )

◆ CPPUNIT_TEST() [18/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalHex27Tangled  )

◆ CPPUNIT_TEST() [19/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalHex27MultipleSubdomains  )

◆ CPPUNIT_TEST() [20/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPyramid5  )

◆ CPPUNIT_TEST() [21/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPyramid13  )

◆ CPPUNIT_TEST() [22/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPyramid14  )

◆ CPPUNIT_TEST() [23/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPyramid18  )

◆ CPPUNIT_TEST() [24/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPyramid18MultipleSubdomains  )

◆ CPPUNIT_TEST() [25/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPrism6  )

◆ CPPUNIT_TEST() [26/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPrism15  )

◆ CPPUNIT_TEST() [27/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPrism18  )

◆ CPPUNIT_TEST() [28/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPrism20  )

◆ CPPUNIT_TEST() [29/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPrism21  )

◆ CPPUNIT_TEST() [30/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalPrism21MultipleSubdomains  )

◆ CPPUNIT_TEST() [31/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalTet4  )

◆ CPPUNIT_TEST() [32/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalTet10  )

◆ CPPUNIT_TEST() [33/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalTet14  )

◆ CPPUNIT_TEST() [34/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalTet14MultipleSubdomains  )

◆ CPPUNIT_TEST() [35/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalMixed2D  )

◆ CPPUNIT_TEST() [36/36]

MeshSmootherTest::CPPUNIT_TEST ( testVariationalMixed3D  )

◆ 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.

◆ numCenteredAndFacedDimensions()

std::pair<unsigned int, unsigned int> MeshSmootherTest::numCenteredAndFacedDimensions ( const Point point,
const Real &  side_length,
const Real &  tol 
)
inline

Definition at line 357 of file mesh_smoother_test.C.

References libMesh::make_range().

358  {
359  const auto half_length = 0.5 * side_length;
360  unsigned int num_centered = 0;
361  unsigned int num_face = 0;
362  for (const auto d : make_range(3))
363  {
364  const auto num_half_lengths = point(d) / half_length;
365  if (std::abs(num_half_lengths - std::round(num_half_lengths)) > tol)
366  // This coordinante does not occur at a sub-cube face or center
367  continue;
368 
369  if (std::lround(num_half_lengths) % 2)
370  // An odd number of half lengths means point(d) is at a sub-cube center
371  ++num_centered;
372  else
373  // An odd number of half lengths means point(d) is on a sub-cube face
374  ++num_face;
375  }
376 
377  return std::make_pair(num_centered, num_face);
378  }
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...
Definition: int_range.h:176

◆ pointIsCubeCenter()

bool MeshSmootherTest::pointIsCubeCenter ( const Point point,
const Real &  side_length,
const Real &  tol = TOLERANCE 
)
inline

Definition at line 382 of file mesh_smoother_test.C.

383  {
384  return numCenteredAndFacedDimensions(point, side_length, tol).first == 3;
385  }
std::pair< unsigned int, unsigned int > numCenteredAndFacedDimensions(const Point &point, const Real &side_length, const Real &tol)

◆ pointIsCubeFaceCenter()

bool MeshSmootherTest::pointIsCubeFaceCenter ( const Point point,
const Real &  side_length,
const Real &  tol = TOLERANCE 
)
inline

Definition at line 396 of file mesh_smoother_test.C.

397  {
398  const auto result = numCenteredAndFacedDimensions(point, side_length, tol);
399  return (result.first == 2) && (result.second == 1);
400  }
std::pair< unsigned int, unsigned int > numCenteredAndFacedDimensions(const Point &point, const Real &side_length, const Real &tol)

◆ pointIsCubeVertex()

bool MeshSmootherTest::pointIsCubeVertex ( const Point point,
const Real &  side_length,
const Real &  tol = TOLERANCE 
)
inline

Definition at line 389 of file mesh_smoother_test.C.

390  {
391  return numCenteredAndFacedDimensions(point, side_length, tol).second == 3;
392  }
std::pair< unsigned int, unsigned int > numCenteredAndFacedDimensions(const Point &point, const Real &side_length, const Real &tol)

◆ setUp()

void MeshSmootherTest::setUp ( )
inline

Definition at line 284 of file mesh_smoother_test.C.

284 {}

◆ tearDown()

void MeshSmootherTest::tearDown ( )
inline

Definition at line 286 of file mesh_smoother_test.C.

286 {}

◆ testLaplaceQuad()

void MeshSmootherTest::testLaplaceQuad ( )
inline

Definition at line 1066 of file mesh_smoother_test.C.

References mesh, libMesh::QUAD4, and TestCommWorld.

1067  {
1069  LaplaceMeshSmoother laplace(mesh, 8);
1070 
1071  testLaplaceSmoother(mesh, laplace, QUAD4);
1072  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
void testLaplaceSmoother(ReplicatedMesh &mesh, MeshSmoother &smoother, ElemType type)
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
This class defines the data structures necessary for Laplace smoothing.

◆ testLaplaceSmoother()

void MeshSmootherTest::testLaplaceSmoother ( ReplicatedMesh mesh,
MeshSmoother smoother,
ElemType  type 
)
inline

Definition at line 288 of file mesh_smoother_test.C.

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

289  {
290  LOG_UNIT_TEST;
291 
292  constexpr unsigned int n_elems_per_side = 4;
293 
295  mesh, n_elems_per_side, n_elems_per_side, 0., 1., 0., 1., type);
296 
297  // Move it around so we have something that needs smoothing
298  DistortSquare ds;
300 
301  // Assert the distortion is as expected
302  auto center_distortion_is =
303  [](const Node & node, int d, bool distortion, Real distortion_tol = TOLERANCE) {
304  const Real r = node(d);
305  const Real R = r * n_elems_per_side;
306  CPPUNIT_ASSERT_GREATER(-TOLERANCE * TOLERANCE, r);
307  CPPUNIT_ASSERT_GREATER(-TOLERANCE * TOLERANCE, 1 - r);
308 
309  // If we're at the boundaries we should *never* be distorted
310  if (std::abs(node(0)) < TOLERANCE * TOLERANCE ||
311  std::abs(node(0) - 1) < TOLERANCE * TOLERANCE)
312  {
313  const Real R1 = node(1) * n_elems_per_side;
314  CPPUNIT_ASSERT_LESS(TOLERANCE * TOLERANCE, std::abs(R1 - std::round(R1)));
315  return true;
316  }
317 
318  if (std::abs(node(1)) < TOLERANCE * TOLERANCE ||
319  std::abs(node(1) - 1) < TOLERANCE * TOLERANCE)
320  {
321  const Real R0 = node(0) * n_elems_per_side;
322  CPPUNIT_ASSERT_LESS(TOLERANCE * TOLERANCE, std::abs(R0 - std::round(R0)));
323 
324  return true;
325  }
326 
327  // If we're at the center we're fine
328  if (std::abs(r - 0.5) < TOLERANCE * TOLERANCE)
329  return true;
330 
331  return ((std::abs(R - std::round(R)) > distortion_tol) == distortion);
332  };
333 
334  for (auto node : mesh.node_ptr_range())
335  {
336  CPPUNIT_ASSERT(center_distortion_is(*node, 0, true));
337  CPPUNIT_ASSERT(center_distortion_is(*node, 1, true));
338  }
339 
340  // Enough iterations to mostly fix us up. Laplace seems to be at 1e-3
341  // tolerance by iteration 6, so hopefully everything is there on any
342  // system by 8.
343  for (unsigned int i = 0; i != 8; ++i)
344  smoother.smooth();
345 
346  // Make sure we're not too distorted anymore.
347  for (auto node : mesh.node_ptr_range())
348  {
349  CPPUNIT_ASSERT(center_distortion_is(*node, 0, false, 1e-3));
350  CPPUNIT_ASSERT(center_distortion_is(*node, 1, false, 1e-3));
351  }
352  }
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.
virtual void smooth()=0
Function which actually performs the smoothing operations.
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void redistribute(MeshBase &mesh, const FunctionBase< Real > &mapfunc)
Deterministically perturb the nodal locations.

◆ testLaplaceTri()

void MeshSmootherTest::testLaplaceTri ( )
inline

Definition at line 1074 of file mesh_smoother_test.C.

References mesh, TestCommWorld, and libMesh::TRI3.

1075  {
1077  LaplaceMeshSmoother laplace(mesh, 8);
1078 
1079  testLaplaceSmoother(mesh, laplace, TRI3);
1080  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
void testLaplaceSmoother(ReplicatedMesh &mesh, MeshSmoother &smoother, ElemType type)
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
This class defines the data structures necessary for Laplace smoothing.

◆ testVariationalEdge2()

void MeshSmootherTest::testVariationalEdge2 ( )
inline

Definition at line 1083 of file mesh_smoother_test.C.

References libMesh::EDGE2, mesh, and TestCommWorld.

1084  {
1086  VariationalMeshSmoother variational(mesh);
1087 
1088  testVariationalSmoother(mesh, variational, EDGE2);
1089  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalEdge3()

void MeshSmootherTest::testVariationalEdge3 ( )
inline

Definition at line 1091 of file mesh_smoother_test.C.

References libMesh::EDGE3, mesh, and TestCommWorld.

1092  {
1094  VariationalMeshSmoother variational(mesh);
1095 
1096  testVariationalSmoother(mesh, variational, EDGE3);
1097  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalEdge3MultipleSubdomains()

void MeshSmootherTest::testVariationalEdge3MultipleSubdomains ( )
inline

Definition at line 1099 of file mesh_smoother_test.C.

References libMesh::EDGE3, mesh, and TestCommWorld.

1100  {
1102  VariationalMeshSmoother variational(mesh);
1103 
1104  testVariationalSmoother(mesh, variational, EDGE3, true);
1105  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalHex20()

void MeshSmootherTest::testVariationalHex20 ( )
inline

Definition at line 1195 of file mesh_smoother_test.C.

References libMesh::HEX20, mesh, and TestCommWorld.

1196  {
1198  VariationalMeshSmoother variational(mesh);
1199 
1200  testVariationalSmoother(mesh, variational, HEX20);
1201  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalHex27()

void MeshSmootherTest::testVariationalHex27 ( )
inline

Definition at line 1203 of file mesh_smoother_test.C.

References libMesh::HEX27, mesh, and TestCommWorld.

1204  {
1206  VariationalMeshSmoother variational(mesh);
1207 
1208  testVariationalSmoother(mesh, variational, HEX27);
1209  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalHex27MultipleSubdomains()

void MeshSmootherTest::testVariationalHex27MultipleSubdomains ( )
inline

Definition at line 1211 of file mesh_smoother_test.C.

References libMesh::HEX27, mesh, and TestCommWorld.

1212  {
1214  VariationalMeshSmoother variational(mesh);
1215 
1216  testVariationalSmoother(mesh, variational, HEX27, true);
1217  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalHex27Tangled()

void MeshSmootherTest::testVariationalHex27Tangled ( )
inline

Definition at line 1219 of file mesh_smoother_test.C.

References libMesh::HEX27, mesh, and TestCommWorld.

1220  {
1222  VariationalMeshSmoother variational(mesh);
1223 
1224  testVariationalSmoother(mesh, variational, HEX27, false, true, 0.55);
1225  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalHex8()

void MeshSmootherTest::testVariationalHex8 ( )
inline

Definition at line 1187 of file mesh_smoother_test.C.

References libMesh::HEX8, mesh, and TestCommWorld.

1188  {
1190  VariationalMeshSmoother variational(mesh);
1191 
1192  testVariationalSmoother(mesh, variational, HEX8);
1193  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalMixed2D()

void MeshSmootherTest::testVariationalMixed2D ( )
inline

Definition at line 1359 of file mesh_smoother_test.C.

References mesh, libMesh::MeshBase::read(), and TestCommWorld.

1360  {
1362  mesh.read("meshes/quad4_tri3_smoothed.xda.gz");
1363 
1365  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false, bool skip_detect_interior_parents=false)=0
Interfaces for reading/writing a mesh to/from a file.
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmootherRegression(const ReplicatedMesh &gold_mesh)

◆ testVariationalMixed3D()

void MeshSmootherTest::testVariationalMixed3D ( )
inline

Definition at line 1367 of file mesh_smoother_test.C.

References mesh, libMesh::MeshBase::read(), and TestCommWorld.

1368  {
1370  mesh.read("meshes/hex8_prism6_smoothed.xda.gz");
1371 
1373  }
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
virtual void read(const std::string &name, void *mesh_data=nullptr, bool skip_renumber_nodes_and_elements=false, bool skip_find_neighbors=false, bool skip_detect_interior_parents=false)=0
Interfaces for reading/writing a mesh to/from a file.
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmootherRegression(const ReplicatedMesh &gold_mesh)

◆ testVariationalPrism15()

void MeshSmootherTest::testVariationalPrism15 ( )
inline

Definition at line 1275 of file mesh_smoother_test.C.

References mesh, libMesh::PRISM15, and TestCommWorld.

1276  {
1278  VariationalMeshSmoother variational(mesh);
1279 
1280  testVariationalSmoother(mesh, variational, PRISM15);
1281  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalPrism18()

void MeshSmootherTest::testVariationalPrism18 ( )
inline

Definition at line 1283 of file mesh_smoother_test.C.

References mesh, libMesh::PRISM18, TestCommWorld, and libMesh::TOLERANCE.

1284  {
1286  VariationalMeshSmoother variational(
1287  mesh, 0.5, true, TOLERANCE * TOLERANCE, 10 * TOLERANCE * TOLERANCE);
1288 
1289  testVariationalSmoother(mesh, variational, PRISM18);
1290  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalPrism20()

void MeshSmootherTest::testVariationalPrism20 ( )
inline

Definition at line 1292 of file mesh_smoother_test.C.

References mesh, libMesh::PRISM20, TestCommWorld, and libMesh::TOLERANCE.

1293  {
1295  VariationalMeshSmoother variational(
1296  mesh, 0.5, true, TOLERANCE * TOLERANCE, 10 * TOLERANCE * TOLERANCE);
1297 
1298  testVariationalSmoother(mesh, variational, PRISM20);
1299  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalPrism21()

void MeshSmootherTest::testVariationalPrism21 ( )
inline

Definition at line 1301 of file mesh_smoother_test.C.

References mesh, libMesh::PRISM21, TestCommWorld, and libMesh::TOLERANCE.

1302  {
1304  VariationalMeshSmoother variational(
1305  mesh, 0.5, true, TOLERANCE * TOLERANCE, 10 * TOLERANCE * TOLERANCE);
1306 
1307  testVariationalSmoother(mesh, variational, PRISM21);
1308  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalPrism21MultipleSubdomains()

void MeshSmootherTest::testVariationalPrism21MultipleSubdomains ( )
inline

Definition at line 1310 of file mesh_smoother_test.C.

References libMesh::MeshBase::allow_renumbering(), mesh, libMesh::PRISM21, and TestCommWorld.

1311  {
1313  mesh.allow_renumbering(false);
1314  VariationalMeshSmoother variational(mesh);
1315 
1316  testVariationalSmoother(mesh, variational, PRISM21, true);
1317  }
void allow_renumbering(bool allow)
If false is passed in then this mesh will no longer be renumbered when being prepared for use...
Definition: mesh_base.h:1345
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalPrism6()

void MeshSmootherTest::testVariationalPrism6 ( )
inline

Definition at line 1267 of file mesh_smoother_test.C.

References mesh, libMesh::PRISM6, and TestCommWorld.

1268  {
1270  VariationalMeshSmoother variational(mesh);
1271 
1272  testVariationalSmoother(mesh, variational, PRISM6);
1273  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalPyramid13()

void MeshSmootherTest::testVariationalPyramid13 ( )
inline

Definition at line 1235 of file mesh_smoother_test.C.

References mesh, libMesh::PYRAMID13, and TestCommWorld.

1236  {
1238  VariationalMeshSmoother variational(mesh);
1239 
1240  testVariationalSmoother(mesh, variational, PYRAMID13);
1241  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalPyramid14()

void MeshSmootherTest::testVariationalPyramid14 ( )
inline

Definition at line 1243 of file mesh_smoother_test.C.

References mesh, libMesh::PYRAMID14, and TestCommWorld.

1244  {
1246  VariationalMeshSmoother variational(mesh);
1247 
1248  testVariationalSmoother(mesh, variational, PYRAMID14);
1249  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalPyramid18()

void MeshSmootherTest::testVariationalPyramid18 ( )
inline

Definition at line 1251 of file mesh_smoother_test.C.

References mesh, libMesh::PYRAMID18, and TestCommWorld.

1252  {
1254  VariationalMeshSmoother variational(mesh);
1255 
1256  testVariationalSmoother(mesh, variational, PYRAMID18);
1257  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalPyramid18MultipleSubdomains()

void MeshSmootherTest::testVariationalPyramid18MultipleSubdomains ( )
inline

Definition at line 1259 of file mesh_smoother_test.C.

References mesh, libMesh::PYRAMID18, and TestCommWorld.

1260  {
1262  VariationalMeshSmoother variational(mesh, 0.0);
1263 
1264  testVariationalSmoother(mesh, variational, PYRAMID18, true);
1265  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalPyramid5()

void MeshSmootherTest::testVariationalPyramid5 ( )
inline

Definition at line 1227 of file mesh_smoother_test.C.

References mesh, libMesh::PYRAMID5, and TestCommWorld.

1228  {
1230  VariationalMeshSmoother variational(mesh);
1231 
1232  testVariationalSmoother(mesh, variational, PYRAMID5);
1233  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalQuad4()

void MeshSmootherTest::testVariationalQuad4 ( )
inline

Definition at line 1107 of file mesh_smoother_test.C.

References mesh, libMesh::out, libMesh::QUAD4, libMesh::BasicOStreamProxy< charT, traits >::rdbuf(), TestCommWorld, and libMesh::TOLERANCE.

1108  {
1110  VariationalMeshSmoother variational(mesh, 0.5, true, TOLERANCE * TOLERANCE, TOLERANCE * TOLERANCE, 100);
1111 
1112  // High verbosity for a 3D mesh to increase code coverage, but silence the output
1113  // If we want to save the output for processing later, send it somewhere
1114  // besides nullptr
1115  std::streambuf * out_buf = libMesh::out.rdbuf(nullptr);
1116 
1117  testVariationalSmoother(mesh, variational, QUAD4);
1118 
1119  // Reset stdout
1120  libMesh::out.rdbuf(out_buf);
1121  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
streambufT * rdbuf() const
Get the associated stream buffer.
This is an implementation of Larisa Branets&#39; smoothing algorithms.
OStreamProxy out
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalQuad4MultipleSubdomains()

void MeshSmootherTest::testVariationalQuad4MultipleSubdomains ( )
inline

Definition at line 1123 of file mesh_smoother_test.C.

References mesh, libMesh::QUAD4, and TestCommWorld.

1124  {
1126  VariationalMeshSmoother variational(mesh);
1127 
1128  testVariationalSmoother(mesh, variational, QUAD4, true);
1129  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalQuad4Tangled()

void MeshSmootherTest::testVariationalQuad4Tangled ( )
inline

Definition at line 1155 of file mesh_smoother_test.C.

References mesh, libMesh::QUAD4, and TestCommWorld.

1156  {
1158  VariationalMeshSmoother variational(mesh);
1159 
1160  testVariationalSmoother(mesh, variational, QUAD4, false, true, 0.65);
1161  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalQuad8()

void MeshSmootherTest::testVariationalQuad8 ( )
inline

Definition at line 1131 of file mesh_smoother_test.C.

References mesh, libMesh::QUAD8, and TestCommWorld.

1132  {
1134  VariationalMeshSmoother variational(mesh);
1135 
1136  testVariationalSmoother(mesh, variational, QUAD8);
1137  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalQuad9()

void MeshSmootherTest::testVariationalQuad9 ( )
inline

Definition at line 1139 of file mesh_smoother_test.C.

References mesh, libMesh::QUAD9, and TestCommWorld.

1140  {
1142  VariationalMeshSmoother variational(mesh);
1143 
1144  testVariationalSmoother(mesh, variational, QUAD9);
1145  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalQuad9MultipleSubdomains()

void MeshSmootherTest::testVariationalQuad9MultipleSubdomains ( )
inline

Definition at line 1147 of file mesh_smoother_test.C.

References mesh, libMesh::QUAD9, and TestCommWorld.

1148  {
1150  VariationalMeshSmoother variational(mesh);
1151 
1152  testVariationalSmoother(mesh, variational, QUAD9, true);
1153  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalSmoother()

void MeshSmootherTest::testVariationalSmoother ( Mesh mesh,
VariationalMeshSmoother smoother,
const ElemType  type,
const bool  multiple_subdomains = false,
const bool  tangle_mesh = false,
const Real  tangle_damping_factor = 1.0 
)
inline

Definition at line 402 of file mesh_smoother_test.C.

References libMesh::absolute_fuzzy_equals(), b, TIMPI::Communicator::broadcast(), libMesh::MeshTools::Generation::build_cube(), libMesh::MeshTools::Generation::build_line(), libMesh::MeshTools::build_nodes_to_elem_map(), libMesh::MeshTools::Generation::build_square(), libMesh::MeshBase::cache_elem_data(), libMesh::ParallelObject::comm(), dim, libMesh::MeshBase::elem_default_orders(), libMesh::Utility::enum_to_string(), libMesh::MeshTools::find_nodal_or_face_neighbors(), libMesh::ReferenceElem::get(), libMesh::MeshBase::get_boundary_info(), libMesh::VariationalMeshSmoother::get_mesh_info(), libMesh::DofObject::invalid_id, libMesh::libmesh_assert(), libMesh::make_range(), TIMPI::Communicator::max(), mesh, TIMPI::Communicator::min(), libMesh::MeshBase::node_ref(), libMesh::TensorTools::norm(), libMesh::ParallelObject::processor_id(), libMesh::PYRAMID18, libMesh::MeshBase::query_node_ptr(), libMesh::Real, libMesh::MeshTools::Modification::redistribute(), libMesh::relative_fuzzy_equals(), libMesh::VariationalMeshSmoother::setup(), libMesh::VariationalMeshSmoother::smooth(), TIMPI::Communicator::sum(), libMesh::Parallel::sync_dofobject_data_by_id(), libMesh::TET10, libMesh::TOLERANCE, libMesh::Elem::type_to_default_order_map, and libMesh::MeshTools::weight().

408  {
409  LOG_UNIT_TEST;
410 
411  if (multiple_subdomains && tangle_mesh)
412  libmesh_not_implemented_msg(
413  "Arbitrary mesh tangling with multiple subdomains is not supported.");
414 
415  // Get mesh dimension, determine whether type is triangular
416  const auto * ref_elem = &(ReferenceElem::get(type));
417  const auto dim = ref_elem->dim();
418  const bool type_is_tri = Utility::enum_to_string(type).compare(0, 3, "TRI") == 0;
419  const bool type_is_pyramid = Utility::enum_to_string(type).compare(0, 7, "PYRAMID") == 0;
420  const bool type_is_prism = Utility::enum_to_string(type).compare(0, 5, "PRISM") == 0;
421  const bool type_is_tet = Utility::enum_to_string(type).compare(0, 3, "TET") == 0;
422 
423  // Used fewer elems for higher order types, as extra midpoint nodes will add
424  // enough complexity
425  unsigned int n_elems_per_side = 4 / Elem::type_to_default_order_map[type];
426  const auto side_length = 1.0 / n_elems_per_side;
427 
428  switch (dim)
429  {
430  case 1:
431  MeshTools::Generation::build_line(mesh, n_elems_per_side, 0., 1., type);
432  break;
433  case 2:
435  mesh, n_elems_per_side, n_elems_per_side, 0., 1., 0., 1., type);
436  break;
437 
438  case 3:
440  n_elems_per_side,
441  n_elems_per_side,
442  n_elems_per_side,
443  0.,
444  1.,
445  0.,
446  1.,
447  0.,
448  1.,
449  type);
450  break;
451 
452  default:
453  libmesh_error_msg("Unsupported dimension " << dim);
454  }
455 
456  // Move it around so we have something that needs smoothing
457  DistortHyperCube dh(dim);
459 
460  const auto & boundary_info = mesh.get_boundary_info();
461  const auto & proc_id = mesh.processor_id();
462 
463  if (tangle_mesh)
464  {
465  // We tangle the mesh by (partially) swapping the locations of 2 nodes.
466  // If the n-dimentional hypercube is represented as a grid with
467  // (undistorted) divisions occuring at integer numbers, we will
468  // (partially) swap the nodes nearest p1 = (1,1,1) and p2 = (2,1,2).
469 
470  // Define p1 and p2 given the integer indices
471  // Undistorted elem side length
472  const Real dr = 1. / (n_elems_per_side * Elem::type_to_default_order_map[type]);
473  const Point p1 = Point(dr, dim > 1 ? dr : 0, dim > 2 ? dr : 0);
474  const Point p2 = Point(2. * dr, dim > 1 ? dr : 0, dim > 2 ? 2. * dr : 0);
475 
476  // We need to find the nodes of the mesh that are closest to p1 and p2.
477  // This will require some parallel communication for distributed meshes.
478 
479  // Distances between local mesh nodes and p1
480  std::map<dof_id_type, Real> dist1_map;
481  // Distances between local mesh nodes and p2
482  std::map<dof_id_type, Real> dist2_map;
483 
484  for (const auto * node : mesh.local_node_ptr_range())
485  {
486  dist1_map[node->id()] = (*node - p1).norm();
487  dist2_map[node->id()] = (*node - p2).norm();
488  }
489 
490  // Helper function to analyze a dist_map accross all processors and
491  // return the node id and spatial coordinates for the node with the
492  // smallest distance
493  auto get_closet_point_accross_all_procs =
494  [&mesh, &proc_id](const std::map<dof_id_type, Real> &dist_map) {
495 
496  processor_id_type broadcasting_proc = 0;
497  Real d_min_local = std::numeric_limits<Real>::max();
498  dof_id_type node_id = DofObject::invalid_id;
499 
500  // Only execute this if this proc owns any nodes. Otherwise,
501  // use default values defined above
502  if (dist_map.size())
503  {
504  // Iterator to the map entry with the smallest distance
505  auto min_it =
506  std::min_element(dist_map.begin(), dist_map.end(),
507  [](const auto &a, const auto &b) {
508  return a.second < b.second;
509  });
510 
511  node_id = min_it->first;
512  d_min_local = min_it->second;
513  }
514 
515  // Get the smallest distance accross all procs
516  auto d_min_global = d_min_local;
517  mesh.comm().min(d_min_global);
518 
519  // Find the proc id, node_id, and spatial coordinantes for the
520  // node with the smallest distance
521  Point node;
522  if (d_min_local == d_min_global) {
523  broadcasting_proc = proc_id;
524  node = mesh.node_ref(node_id);
525  }
526 
527  mesh.comm().max(broadcasting_proc);
528  // Broadcast information about this node to all procs
529  mesh.comm().broadcast(node_id, broadcasting_proc);
530  mesh.comm().broadcast(node, broadcasting_proc);
531 
532  return std::pair(node_id, node);
533  };
534 
535  const auto [node_id1, node1] =
536  get_closet_point_accross_all_procs(dist1_map);
537  const auto [node_id2, node2] =
538  get_closet_point_accross_all_procs(dist2_map);
539 
540  // modify the nodes if they are on this proc
541  const auto displacement = tangle_damping_factor * (node1 - node2);
542  if (mesh.query_node_ptr(node_id1))
543  mesh.node_ref(node_id1) -= displacement;
544  if (mesh.query_node_ptr(node_id2))
545  mesh.node_ref(node_id2) += displacement;
546 
547  SyncNodalPositions sync_object(mesh);
549  mesh.nodes_end(), sync_object);
550 
551  // Make sure the mesh is tangled
552  // Need this to create the system we are about to access
553  smoother.setup();
554  const auto &unsmoothed_info = smoother.get_mesh_info();
555  CPPUNIT_ASSERT(unsmoothed_info.mesh_is_tangled);
556  }
557 
558  // Add multiple subdomains if requested
559  std::unordered_map<subdomain_id_type, Real> distorted_subdomain_volumes;
560  subdomain_id_type highest_subdomain_id = 0;
561  if (multiple_subdomains)
562  {
563  // Modify the subdomain ids in an interesting way
564  for (auto * elem : mesh.active_element_ptr_range())
565  {
566  unsigned int subdomain_id = 0;
567  for (const auto d : make_range(dim))
568  if (elem->vertex_average()(d) > 0.5)
569  ++subdomain_id;
570  elem->subdomain_id() += subdomain_id;
571  }
572 
573  // This loop should NOT be combined with the one above because we need to
574  // finish checking and updating subdomain ids for all elements before
575  // recording the final subdomain volumes.
576  for (auto *elem : mesh.active_element_ptr_range()) {
577  const auto sub_id = elem->subdomain_id();
578  // Don't double count an element's volume on multiple procs
579  if (elem->processor_id() != proc_id)
580  continue;
581  distorted_subdomain_volumes[sub_id] += elem->volume();
582  highest_subdomain_id = std::max(sub_id, highest_subdomain_id);
583  }
584 
585  // Parallel communication
586  mesh.comm().max(highest_subdomain_id);
587  for (const auto sub_id : make_range(highest_subdomain_id + 1)) {
588  // Make sure sub_id exists in the map on this proc
589  if (distorted_subdomain_volumes.find(sub_id) ==
590  distorted_subdomain_volumes.end())
591  distorted_subdomain_volumes[sub_id] = 0.;
592 
593  mesh.comm().sum(distorted_subdomain_volumes[sub_id]);
594  }
595 
596  // We've just invalidated the get_mesh_subdomains() cache by
597  // adding a new one; fix it.
599  }
600 
601  // Get the mesh order
602  const auto & elem_orders = mesh.elem_default_orders();
603  libmesh_error_msg_if(elem_orders.size() != 1,
604  "The variational smoother cannot be used for mixed-order meshes!");
605  // For pyramids, the factor 2 accounts for the account that cubes of side
606  // length s are divided into pyramids of base side length s and height s/2.
607  // The factor 4 lets us catch triangular face midpoint nodes for PYRAMID18 elements.
608  // Similar reasoning for tets.
609  const auto scale_factor = *elem_orders.begin() * ((type_is_pyramid || type_is_tet) ? 2 * 4 : 1);
610 
611  // Function to assert the node distortion is as expected
612  auto node_distortion_is = [&n_elems_per_side, &dim, &boundary_info, &scale_factor, &type_is_prism](
613  const Node & node, bool distortion, Real distortion_tol = TOLERANCE) {
614  // Get boundary ids associated with the node
615  std::vector<boundary_id_type> boundary_ids;
616  boundary_info.boundary_ids(&node, boundary_ids);
617 
618  // This tells us what type of node we are: internal, sliding, or fixed
619  const auto num_dofs = dim - boundary_ids.size();
620  /*
621  * The following cases of num_dofs are possible, ASSUMING all boundaries
622  * are non-overlapping
623  * 3D: 3-0, 3-1, 3-2, 3-3
624  * = 3 2 1 0
625  * internal sliding, sliding, fixed
626  * 2D: 2-0, 2-1, 2-2
627  * = 2 1 0
628  * internal sliding, fixed
629  * 1D: 1-0, 1-1
630  * = 1 0
631  * internal fixed
632  *
633  * We expect that R is an integer in [0, n_elems_per_side] for
634  * num_dofs of the node's cooridinantes, while the remaining coordinates
635  * are fixed to the boundary with value 0 or 1. In other words, at LEAST
636  * dim - num_dofs coordinantes should be 0 or 1.
637  */
638 
639  std::size_t num_zero_or_one = 0;
640 
641  bool distorted = false;
642  for (const auto d : make_range(dim))
643  {
644  const Real r = node(d);
645  const Real R = r * n_elems_per_side * scale_factor;
646  CPPUNIT_ASSERT_GREATER(-distortion_tol * distortion_tol, r);
647  CPPUNIT_ASSERT_GREATER(-distortion_tol * distortion_tol, 1 - r);
648 
649  bool d_distorted = std::abs(R - std::round(R)) > distortion_tol;
650  if (type_is_prism && (scale_factor == 3))
651  {
652  // Adjustment required for triangular face nodes of PRISM20/21 elements.
653  // These elements have fe_order 3. This takes care of nodes occuring at
654  // thirds, but not halves.
655  const Real R_prism = R / scale_factor * 2;
656  const bool d_distorted_prism =
657  std::abs(R_prism - std::round(R_prism)) > distortion_tol;
658  d_distorted &= d_distorted_prism;
659  }
660  distorted |= d_distorted;
661  num_zero_or_one += (absolute_fuzzy_equals(r, 0.) || absolute_fuzzy_equals(r, 1.));
662  }
663 
664  CPPUNIT_ASSERT_GREATEREQUAL(dim - num_dofs, num_zero_or_one);
665 
666  // We can never expect a fixed node to be distorted
667  if (num_dofs == 0)
668  // if (num_dofs < dim)
669  return true;
670  return distorted == distortion;
671  };
672 
673  // Make sure our DistortHyperCube transformation has distorted the mesh
674  for (auto node : mesh.node_ptr_range())
675  CPPUNIT_ASSERT(node_distortion_is(*node, true));
676 
677  // Transform the square mesh of triangles to a parallelogram mesh of
678  // triangles. This will allow the Variational Smoother to smooth the mesh
679  // to the optimal case of equilateral triangles
680  if (type_is_tri)
681  {
682  // Transform the square mesh of triangles to a parallelogram mesh of
683  // triangles. This will allow the Variational Smoother to smooth the mesh
684  // to the optimal case of equilateral triangles
685  SquareToParallelogram stp;
687  }
688  else if (type_is_prism)
689  {
690  // Transform the cube mesh of prisms to a parallelepiped mesh of
691  // prisms. This will allow the Variational Smoother to smooth the mesh
692  // to the optimal case of equilateral triangular prisms
693  CubeToParallelepiped ctp;
695  }
696 
697  smoother.smooth();
698 
699  if (type_is_tri)
700  {
701  // Transform the parallelogram mesh back to a square mesh. In the case of
702  // the Variational Smoother, equilateral triangules will be transformed
703  // into right triangules that align with the original undistorted mesh.
704  ParallelogramToSquare pts;
706  }
707  else if (type_is_prism)
708  {
709  // Transform the parallelepiped mesh back to a cube mesh. In the case of
710  // the Variational Smoother, equilateral triangular prisms will be transformed
711  // into right triangular prisms that align with the original undistorted mesh.
712  ParallelepipedToCube ptc;
714  }
715 
716  if (multiple_subdomains)
717  {
718  // Make sure the subdomain volumes didn't change. Although this doesn't
719  // guarantee that the subdomain didn't change, it is a good indicator
720  // and is friedly to sliding subdomain boundary nodes.
721  std::unordered_map<subdomain_id_type, Real> smoothed_subdomain_volumes;
722  for (auto *elem : mesh.active_element_ptr_range()) {
723  // Don't double count an element's volume on multiple procs
724  if (elem->processor_id() != proc_id)
725  continue;
726  smoothed_subdomain_volumes[elem->subdomain_id()] += elem->volume();
727  }
728 
729  // Parallel communication
730  for (const auto sub_id : make_range(highest_subdomain_id + 1)) {
731  // Make sure sub_id exists in the map on this proc
732  if (smoothed_subdomain_volumes.find(sub_id) ==
733  smoothed_subdomain_volumes.end())
734  smoothed_subdomain_volumes[sub_id] = 0.;
735 
736  mesh.comm().sum(smoothed_subdomain_volumes[sub_id]);
737  }
738 
739  for (const auto sub_id : make_range(highest_subdomain_id + 1))
740  CPPUNIT_ASSERT(relative_fuzzy_equals(
741  libmesh_map_find(distorted_subdomain_volumes, sub_id),
742  libmesh_map_find(smoothed_subdomain_volumes, sub_id), TOLERANCE));
743  }
744  else
745  {
746  std::unordered_map<dof_id_type, std::vector<const Elem *>> nodes_to_elem_map;
747  MeshTools::build_nodes_to_elem_map(mesh, nodes_to_elem_map);
748 
749  // Make sure we're not too distorted anymore, using the given
750  // tolerance.
751  std::set<dof_id_type> nodes_checked;
752  const Real tol = TOLERANCE;
753 
754  for (const auto * elem : mesh.active_element_ptr_range())
755  {
756  for (const auto local_node_id : make_range(elem->n_nodes()))
757  {
758  const auto & node = elem->node_ref(local_node_id);
759  if (nodes_checked.find(node.id()) != nodes_checked.end())
760  continue;
761 
762  nodes_checked.insert(node.id());
763 
764  // Check for special case where pyramidal base-to-apex midpoint
765  // nodes are not smoothed to the actual midpoints.
766  if (type_is_pyramid)
767  {
768  if (local_node_id > 8 && local_node_id < 13)
769  {
770  // Base-Apex midpoint nodes
771  //
772  // Due to the nature of the pyramidal target element and the
773  // cubic nature of the test mesh, for a dilation weight o
774  // 0.5, smoothed base-apex midpoint nodes are smoothed to
775  // the point base + x * (apex - base) instead of
776  // base + 0.5 (apex - base), where x is in (0,1) and
777  // depends on the number of nodes in the element.
778  // We hard-code this check below.
779 
780  const auto & base = elem->node_ref(local_node_id - 9);
781  const auto & apex = elem->node_ref(4);
782  const Real x = (type == PYRAMID18) ? 0.56646084 : 0.54985875;
783 
784  CPPUNIT_ASSERT(node.absolute_fuzzy_equals(base + x * (apex - base), tol));
785  continue;
786  }
787  else if (local_node_id > 13)
788  {
789  // Triangular face midpoint nodes
790  //
791  // Due to the nature of the pyramidal target element and the
792  // cubic nature of the test mesh, for a dilation weight o
793  // 0.5, smoothed triangular face midpoint nodes are
794  // smoothed a weighted average of the constituent
795  // vertices instead of an unweighted average.
796  // We hard-code this check below.
797  const auto & base1 = elem->node_ref(local_node_id - 14);
798  const auto & base2 = elem->node_ref((local_node_id - 13) % 4);
799  const auto & apex = elem->node_ref(4);
800 
801  const auto node_approx =
802  (0.31401599 * base1 + 0.31401599 * base2 + 0.37196802 * apex);
803  CPPUNIT_ASSERT(node.absolute_fuzzy_equals(node_approx, tol));
804  continue;
805  }
806  }
807 
808  // Check for special case where some tet midpoint nodes are not
809  // smoothed to the actual midpoints.
810  else if (type_is_tet && !elem->is_vertex(local_node_id))
811  {
812  // We have a non-vertex node. Determine what "type" of
813  // midpoint node with respect to the mesh geometry.
814  // First, get the nodes that neighbor this node
815  std::vector<const Node *> neighbors;
817  mesh, node, nodes_to_elem_map, neighbors);
818 
819  switch (neighbors.size())
820  {
821  case 2: {
822  // Midpoint node
823  // Determine what "type" of midpoint node
824 
825  // Is one of the neighbors at the center of a sub-cube?
826  const auto is_0_cube_center =
827  pointIsCubeCenter(*neighbors[0], side_length);
828  const auto is_1_cube_center =
829  pointIsCubeCenter(*neighbors[1], side_length);
830  libmesh_assert(!(is_0_cube_center && is_1_cube_center));
831 
832  if (is_0_cube_center || is_1_cube_center)
833  {
834  const auto & cube_center =
835  is_0_cube_center ? *neighbors[0] : *neighbors[1];
836  const auto & other =
837  is_0_cube_center ? *neighbors[1] : *neighbors[0];
838 
839  // Since one neighbor is a sub-cube center, the
840  // other will either be a sub-cube face center or
841  // a sub-cube vertex. Determine which one.
842  if (pointIsCubeFaceCenter(other, side_length))
843  {
844  const Real x = (type == TET10) ? 0.42895041 : 0.41486385;
845  CPPUNIT_ASSERT(node.absolute_fuzzy_equals(
846  other + x * (cube_center - other), tol));
847  }
848 
849  else if (pointIsCubeVertex(other, side_length))
850  {
851  const Real x = (type == TET10) ? 0.55388920 : 0.58093516;
852  CPPUNIT_ASSERT(node.absolute_fuzzy_equals(
853  other + x * (cube_center - other), tol));
854  }
855  }
856 
857  else
858  {
859  // The remaining possibilities are
860  // cube-vertex-to-cube-vertex midpoints and
861  // cube-vertex-to-cube-face-center midpoints.
862  const auto is_0_cube_vertex =
863  pointIsCubeVertex(*neighbors[0], side_length);
864  const auto is_1_cube_vertex =
865  pointIsCubeVertex(*neighbors[1], side_length);
866  const auto is_0_cube_face_center =
867  pointIsCubeFaceCenter(*neighbors[0], side_length);
868  const auto is_1_cube_face_center =
869  pointIsCubeFaceCenter(*neighbors[1], side_length);
870 
871  if (is_0_cube_vertex && is_1_cube_vertex)
872  // Due to symmetry, this type of midpoint is
873  // the geometric midpoint. Let the
874  // node_distortion_is function check it
875  CPPUNIT_ASSERT(node_distortion_is(node, false));
876 
877  else
878  {
879  libmesh_error_msg_if(
880  (is_0_cube_center || is_0_cube_face_center) &&
881  (is_1_cube_center || is_1_cube_face_center),
882  "We should never get here!");
883  const auto & cube_vertex =
884  is_0_cube_vertex ? *neighbors[0] : *neighbors[1];
885  const auto & cube_face_center =
886  is_0_cube_face_center ? *neighbors[0] : *neighbors[1];
887  const Real x = (type == TET10) ? 0.61299101 : 0.65125580;
888  CPPUNIT_ASSERT(node.absolute_fuzzy_equals(
889  cube_vertex + x * (cube_face_center - cube_vertex), tol));
890  }
891  }
892 
893  continue;
894  break;
895  }
896 
897  case 6: {
898  // Face node
899  // Only keep the face vertex nodes
900  neighbors.erase(std::remove_if(neighbors.begin(),
901  neighbors.end(),
902  [&elem](const Node * n) {
903  return !elem->is_vertex(
904  elem->local_node(n->id()));
905  }),
906  neighbors.end());
907 
908  // There are three types of faces:
909  //
910  // 1) Isoscelese triangle with vertices at two
911  // sub-cube vertices and the sub-cube center,
912  // 2) Isosceles triangle with vertices at two
913  // sub-cube vertices and a sub-cube face center,
914  // 3) Scalene triangle with vertices at a sub-cube
915  // center, a sub-cube vertex, and a sub-cube face
916  // center.
917  //
918  // Determine which kind of face this node belongs to based on the vertex
919  // neighbors
920 
921  unsigned int num_vertices_at_cube_center = 0;
922  unsigned int num_vertices_at_cube_vertices = 0;
923  unsigned int num_vertices_at_cube_face_centers = 0;
924  for (const auto * neighbor : neighbors)
925  {
926  if (pointIsCubeCenter(*neighbor, side_length))
927  num_vertices_at_cube_center += 1;
928  else if (pointIsCubeVertex(*neighbor, side_length))
929  num_vertices_at_cube_vertices += 1;
930  else if (pointIsCubeFaceCenter(*neighbor, side_length))
931  num_vertices_at_cube_face_centers += 1;
932  }
933 
934  // We will express the face node at a linear
935  // combination of the face vertices
936  Node node_approx = Node(0, 0, 0);
937 
938  // Isosceles triangular face
939  if (num_vertices_at_cube_vertices == 2)
940  {
941  // Isosceles triangular face (type 1)
942  if (num_vertices_at_cube_center)
943  for (const auto * neighbor : neighbors)
944  {
945  Real weight;
946  if (pointIsCubeVertex(*neighbor, side_length))
947  weight = 0.30600747;
948  else if (pointIsCubeCenter(*neighbor, side_length))
949  weight = 0.38798506;
950  else
951  libmesh_error_msg("We should never get here!");
952 
953  node_approx += weight * (*neighbor);
954  }
955 
956  // Isosceles triangular face (type 2)
957  else if (num_vertices_at_cube_face_centers)
958  for (const auto * neighbor : neighbors)
959  {
960  Real weight;
961  if (pointIsCubeVertex(*neighbor, side_length))
962  weight = 0.28078090;
963  else if (pointIsCubeFaceCenter(*neighbor, side_length))
964  weight = 0.43843820;
965  else
966  libmesh_error_msg("We should never get here!");
967 
968  node_approx += weight * (*neighbor);
969  }
970 
971  else
972  libmesh_error_msg("We should never get here!");
973  }
974 
975  // Scalene triangular face (type 3)
976  else if (num_vertices_at_cube_center && num_vertices_at_cube_vertices &&
977  num_vertices_at_cube_face_centers)
978  for (const auto * neighbor : neighbors)
979  {
980  Real weight;
981  if (pointIsCubeCenter(*neighbor, side_length))
982  weight = 0.33102438;
983  else if (pointIsCubeVertex(*neighbor, side_length))
984  weight = 0.27147230;
985  else if (pointIsCubeFaceCenter(*neighbor, side_length))
986  weight = 0.39750332;
987  else
988  libmesh_error_msg("We should never get here!");
989 
990  node_approx += weight * (*neighbor);
991  }
992 
993  else
994  libmesh_error_msg("We should never get here!");
995 
996  CPPUNIT_ASSERT(node.absolute_fuzzy_equals(node_approx, tol));
997 
998  continue;
999  break;
1000  }
1001  default: {
1002  libmesh_error_msg(node << " has unexpected number of neighbors ("
1003  << neighbors.size() << ")");
1004  break;
1005  }
1006  } // switch (neighbors.size())
1007  } // if (type_is_tet)
1008 
1009  CPPUNIT_ASSERT(node_distortion_is(node, false));
1010 
1011  }
1012  }
1013  }
1014  }
const std::set< Order > & elem_default_orders() const
Definition: mesh_base.h:427
A Node is like a Point, but with more information.
Definition: node.h:52
static constexpr Real TOLERANCE
unsigned int dim
virtual void smooth() override
Redefinition of the smooth function from the base class.
void sum(T &r) const
MeshBase & mesh
const MeshQualityInfo & get_mesh_info() const
Getter for the _system&#39;s _mesh_info attribute.
bool pointIsCubeVertex(const Point &point, const Real &side_length, const Real &tol=TOLERANCE)
const Parallel::Communicator & comm() const
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.
void build_nodes_to_elem_map(const MeshBase &mesh, std::vector< std::vector< dof_id_type >> &nodes_to_elem_map)
After calling this function the input vector nodes_to_elem_map will contain the node to element conne...
Definition: mesh_tools.C:456
const BoundaryInfo & get_boundary_info() const
The information about boundary ids on the mesh.
Definition: mesh_base.h:170
uint8_t processor_id_type
void min(const T &r, T &o, Request &req) const
dof_id_type weight(const MeshBase &mesh, const processor_id_type pid)
Definition: mesh_tools.C:444
bool pointIsCubeFaceCenter(const Point &point, const Real &side_length, const Real &tol=TOLERANCE)
void cache_elem_data()
Definition: mesh_base.C:1959
virtual const Node * query_node_ptr(const dof_id_type i) const =0
libmesh_assert(ctx)
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.
void broadcast(T &data, const unsigned int root_id=0, const bool identical_sizes=false) const
std::string enum_to_string(const T e)
bool absolute_fuzzy_equals(const T &var1, const T2 &var2, const Real tol=TOLERANCE *TOLERANCE)
Function to check whether two variables are equal within an absolute tolerance.
Definition: fuzzy_equals.h:64
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
void max(const T &r, T &o, Request &req) const
auto norm(const T &a)
Definition: tensor_tools.h:74
static const Real b
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...
Definition: int_range.h:176
void redistribute(MeshBase &mesh, const FunctionBase< Real > &mapfunc)
Deterministically perturb the nodal locations.
void build_line(UnstructuredMesh &mesh, const unsigned int nx, const Real xmin=0., const Real xmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
A specialized build_cube() for 1D meshes.
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:735
bool pointIsCubeCenter(const Point &point, const Real &side_length, const Real &tol=TOLERANCE)
bool relative_fuzzy_equals(const T &var1, const T2 &var2, const Real tol=TOLERANCE *TOLERANCE)
Function to check whether two variables are equal within a relative tolerance.
Definition: fuzzy_equals.h:78
void find_nodal_or_face_neighbors(const MeshBase &mesh, const Node &node, const std::unordered_map< dof_id_type, std::vector< const Elem *>> &nodes_to_elem_map, std::vector< const Node *> &neighbors)
Given a mesh and a node in the mesh, the vector will be filled with every node directly attached to t...
Definition: mesh_tools.C:1092
virtual void setup()
Setup method that creates equation systems, system, and constraints, to be called just prior to smoot...
processor_id_type processor_id() const
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
const Elem & get(const ElemType type_in)
void build_cube(UnstructuredMesh &mesh, const unsigned int nx=0, const unsigned int ny=0, const unsigned int nz=0, const Real xmin=0., const Real xmax=1., const Real ymin=0., const Real ymax=1., const Real zmin=0., const Real zmax=1., const ElemType type=INVALID_ELEM, const bool gauss_lobatto_grid=false)
Builds a (elements) cube.
uint8_t dof_id_type
Definition: id_types.h:67

◆ testVariationalSmootherRegression()

void MeshSmootherTest::testVariationalSmootherRegression ( const ReplicatedMesh gold_mesh)
inline

Definition at line 1018 of file mesh_smoother_test.C.

References libMesh::make_range(), mesh, libMesh::MeshBase::mesh_dimension(), libMesh::ReplicatedMesh::n_nodes(), libMesh::MeshBase::n_nodes(), libMesh::MeshBase::node_ref(), libMesh::Real, libMesh::MeshTools::Modification::redistribute(), libMesh::VariationalMeshSmoother::smooth(), and libMesh::TOLERANCE.

1019  {
1020  // Make a copy of the gold mesh to distort and then smooth
1021  ReplicatedMesh mesh(gold_mesh);
1022 
1023  // Move it around so we have something that needs smoothing
1024  DistortHyperCube dh(mesh.mesh_dimension());
1026 
1027  // Function to assert the distortion is as expected
1028  auto mesh_distortion_is = [](const ReplicatedMesh & gold_mesh,
1029  const ReplicatedMesh & mesh,
1030  const bool distortion,
1031  Real distortion_tol = TOLERANCE) {
1032 
1033  CPPUNIT_ASSERT(gold_mesh.n_nodes() == mesh.n_nodes());
1034  for (const auto node_id : make_range(gold_mesh.n_nodes()))
1035  {
1036  const auto & gold_node = gold_mesh.node_ref(node_id);
1037  const auto & node = mesh.node_ref(node_id);
1038  for (const auto d : make_range(gold_mesh.mesh_dimension()))
1039  {
1040  const bool d_distorted = std::abs(gold_node(d) - node(d)) > distortion_tol;
1041  if (d_distorted)
1042  // mesh is distorted from gold_mesh
1043  return distortion;
1044  }
1045  }
1046 
1047  // mesh is not distorted from gold_mesh
1048  return !distortion;
1049  };
1050 
1051  // Make sure the mesh has been distorted
1052  CPPUNIT_ASSERT(mesh_distortion_is(gold_mesh, mesh, true));
1053 
1054  // Turn off subdomain boundary preservation because DistortHyperCube
1055  // does not preserve subdomain boundaries
1056  // Also set dilation coefficient to 0 because the reference volume of the
1057  // distorted mesh won't be equal to the reference volume of the smoothed
1058  // mesh and will smooth to a slightly different solution.
1059  VariationalMeshSmoother smoother(mesh, 0.0, false);
1060  smoother.smooth();
1061 
1062  // Make sure the mesh has been smoothed to the gold mesh
1063  CPPUNIT_ASSERT(mesh_distortion_is(gold_mesh, mesh, false));
1064  }
virtual dof_id_type n_nodes() const override final
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
static constexpr Real TOLERANCE
MeshBase & mesh
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
This is an implementation of Larisa Branets&#39; smoothing algorithms.
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...
Definition: int_range.h:176
unsigned int mesh_dimension() const
Definition: mesh_base.C:430
void redistribute(MeshBase &mesh, const FunctionBase< Real > &mapfunc)
Deterministically perturb the nodal locations.
virtual const Node & node_ref(const dof_id_type i) const
Definition: mesh_base.h:735
virtual dof_id_type n_nodes() const =0

◆ testVariationalTet10()

void MeshSmootherTest::testVariationalTet10 ( )
inline

Definition at line 1335 of file mesh_smoother_test.C.

References mesh, TestCommWorld, and libMesh::TET10.

1336  {
1338  VariationalMeshSmoother variational(mesh);
1339 
1340  testVariationalSmoother(mesh, variational, TET10);
1341  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalTet14()

void MeshSmootherTest::testVariationalTet14 ( )
inline

Definition at line 1343 of file mesh_smoother_test.C.

References mesh, TestCommWorld, and libMesh::TET14.

1344  {
1346  VariationalMeshSmoother variational(mesh);
1347 
1348  testVariationalSmoother(mesh, variational, TET14);
1349  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalTet14MultipleSubdomains()

void MeshSmootherTest::testVariationalTet14MultipleSubdomains ( )
inline

Definition at line 1351 of file mesh_smoother_test.C.

References mesh, TestCommWorld, and libMesh::TET14.

1352  {
1354  VariationalMeshSmoother variational(mesh);
1355 
1356  testVariationalSmoother(mesh, variational, TET14, true);
1357  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalTet4()

void MeshSmootherTest::testVariationalTet4 ( )
inline

Definition at line 1319 of file mesh_smoother_test.C.

References mesh, libMesh::out, libMesh::BasicOStreamProxy< charT, traits >::rdbuf(), TestCommWorld, libMesh::TET4, and libMesh::TOLERANCE.

1320  {
1322  VariationalMeshSmoother variational(mesh, 0.5, true, TOLERANCE * TOLERANCE, TOLERANCE * TOLERANCE, 100);
1323 
1324  // High verbosity for a 3D mesh to increase code coverage, but silence the output
1325  // If we want to save the output for processing later, send it somewhere
1326  // besides nullptr
1327  std::streambuf * out_buf = libMesh::out.rdbuf(nullptr);
1328 
1329  testVariationalSmoother(mesh, variational, TET4);
1330 
1331  // Reset stdout
1332  libMesh::out.rdbuf(out_buf);
1333  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
static constexpr Real TOLERANCE
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
streambufT * rdbuf() const
Get the associated stream buffer.
This is an implementation of Larisa Branets&#39; smoothing algorithms.
OStreamProxy out
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalTri3()

void MeshSmootherTest::testVariationalTri3 ( )
inline

Definition at line 1163 of file mesh_smoother_test.C.

References mesh, TestCommWorld, and libMesh::TRI3.

1164  {
1166  VariationalMeshSmoother variational(mesh);
1167 
1168  testVariationalSmoother(mesh, variational, TRI3);
1169  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalTri6()

void MeshSmootherTest::testVariationalTri6 ( )
inline

Definition at line 1171 of file mesh_smoother_test.C.

References mesh, TestCommWorld, and libMesh::TRI6.

1172  {
1174  VariationalMeshSmoother variational(mesh);
1175 
1176  testVariationalSmoother(mesh, variational, TRI6);
1177  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

◆ testVariationalTri6MultipleSubdomains()

void MeshSmootherTest::testVariationalTri6MultipleSubdomains ( )
inline

Definition at line 1179 of file mesh_smoother_test.C.

References mesh, TestCommWorld, and libMesh::TRI3.

1180  {
1182  VariationalMeshSmoother variational(mesh);
1183 
1184  testVariationalSmoother(mesh, variational, TRI3, true);
1185  }
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:218
MeshBase & mesh
void testVariationalSmoother(Mesh &mesh, VariationalMeshSmoother &smoother, const ElemType type, const bool multiple_subdomains=false, const bool tangle_mesh=false, const Real tangle_damping_factor=1.0)
This is an implementation of Larisa Branets&#39; smoothing algorithms.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50

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