libMesh
libmesh_netgen.C
Go to the documentation of this file.
1 
2 #include "libmesh_cppunit.h"
3 
4 #ifdef LIBMESH_HAVE_NETGEN
5 namespace nglib {
6 #include "netgen/nglib/nglib.h"
7 }
8 
9 using namespace nglib;
10 #endif
11 
12 #include <numeric>
13 
14 class LibMeshNetgenTest : public CppUnit::TestCase {
15 public:
16  LIBMESH_CPPUNIT_TEST_SUITE( LibMeshNetgenTest );
17 
18 #ifdef LIBMESH_HAVE_NETGEN
19  CPPUNIT_TEST( testLibMeshNetgen );
20  CPPUNIT_TEST( testBadHole );
21 
22  // Too expensive to do regularly...
23  // CPPUNIT_TEST( testAllPermutations );
24 #endif
25 
26  CPPUNIT_TEST_SUITE_END();
27 
28 private:
29 
30 public:
31 
32  void setUp()
33  {}
34 
35  void tearDown()
36  {}
37 
38 #ifdef LIBMESH_HAVE_NETGEN
40  {
41  LOG_UNIT_TEST;
42 
43  auto ngmesh = Ng_NewMesh();
44  Ng_DeleteMesh(ngmesh);
45  }
46 
47  std::size_t testPermutedHole (const std::vector<std::size_t> & permutation)
48  {
49  auto ngmesh = Ng_NewMesh();
50 
51  Ng_Meshing_Parameters params;
52  params.elementsperedge = 1;
53  params.elementspercurve = 1;
54 
55  std::vector<std::array<double, 3>> point_coords =
56  {{-4, 4, -4},
57  {-4, 4, 4},
58  {4, 4, 4},
59  {4, -4, 4},
60  {4, 4, -4},
61  {4, -4, -4},
62  {-4, -4, 4},
63  {-4, -4, -4},
64 
65  {3, -3, -3},
66  {-3, -3, 3},
67  {-3, -3, -3},
68  {-3, 3, -3},
69  {-3, 3, 3},
70  {3, 3, 3},
71  {3, -3, 3},
72  {3, 3, -3}};
73 
74  auto n_input_points = point_coords.size();
75 
76  CPPUNIT_ASSERT_EQUAL(permutation.size(), n_input_points);
77 
78  std::vector<std::size_t> inverse_permutation (n_input_points);
79 
80  for (std::size_t i=0; i != n_input_points; ++i)
81  {
82  inverse_permutation[permutation[i]] = i;
83  Ng_AddPoint(ngmesh, point_coords[permutation[i]].data());
84  }
85 
86  std::vector<std::array<int, 3>> tri_nodes =
87  {{1, 2, 3},
88  {4, 3, 2},
89  {5, 1, 3},
90  {5, 3, 4},
91  {1, 5, 6},
92  {6, 5, 4},
93  {6, 4, 7},
94  {7, 4, 2},
95  {8, 1, 6},
96  {8, 6, 7},
97  {1, 8, 2},
98  {8, 7, 2},
99 
100  {11, 10, 9},
101  {11, 9, 12},
102  {10, 11, 13},
103  {13, 12, 14},
104  {12, 13, 11},
105  {9, 10, 15},
106  {13, 14, 15},
107  {13, 15, 10},
108  {15, 14, 16},
109  {16, 14, 12},
110  {15, 16, 9},
111  {9, 16, 12}};
112 
113  for (auto & nodes : tri_nodes)
114  {
115  std::array<int, 3> permuted_nodes = nodes;
116  for (auto & node_i : permuted_nodes)
117  node_i = inverse_permutation[node_i-1]+1;
118  Ng_AddSurfaceElement(ngmesh, NG_TRIG, permuted_nodes.data());
119  }
120 
121  Ng_GenerateVolumeMesh(ngmesh, &params);
122  const std::size_t n_elem = Ng_GetNE(ngmesh);
123  const std::size_t n_points = Ng_GetNP(ngmesh);
124  CPPUNIT_ASSERT_GREATEREQUAL(n_input_points, n_points);
125 
126  std::set<int> nodes_seen;
127  for (std::size_t i = 0; i != n_elem; ++i)
128  {
129  // Avoid segfault even if ngtype isn't a tet4
130  int ngnodes[11];
131  Ng_Volume_Element_Type ngtype =
132  Ng_GetVolumeElement(ngmesh, i+1, ngnodes);
133  CPPUNIT_ASSERT(ngtype == NG_TET);
134  for (int n = 0; n != 4; ++n)
135  if (ngnodes[n] <= int(n_input_points) && ngnodes[n] > 0)
136  nodes_seen.insert(ngnodes[n]);
137  }
138 
139  Ng_DeleteMesh(ngmesh);
140 
141  return nodes_seen.size();
142  }
143 
144  void testBadHole ()
145  {
146  LOG_UNIT_TEST;
147 
148  std::vector<std::size_t> permutation (16);
149  std::iota(permutation.begin(), permutation.end(), 0);
150 
151  int n_original_nodes = testPermutedHole(permutation);
152 
153  CPPUNIT_ASSERT_EQUAL(n_original_nodes, 16);
154  }
155 
157  {
158  LOG_UNIT_TEST;
159 
160  const std::size_t n_input_points = 16;
161 
162  std::vector<std::size_t> permutation (n_input_points);
163  std::iota(permutation.begin(), permutation.end(), 0);
164 
165  int fails=0, successes = 0;
166 
167  auto run_test = [this, &fails, &successes, &permutation]()
168  {
169  int n_original_nodes = testPermutedHole(permutation);
170  fails += (n_original_nodes != n_input_points);
171  successes += (n_original_nodes == n_input_points);
172  std::cout << "Found " << n_original_nodes << "/" << n_input_points << " original nodes\n";
173  std::cout << "Fails = " << fails << ", successes = " << successes << std::endl;
174  };
175 
176  // Heap's Algorithm, non-recursive version
177  run_test();
178 
179  std::vector<std::size_t> c(permutation.size());
180 
181  for (std::size_t i = 1; i != n_input_points ; ++i)
182  {
183  if (c[i] < i)
184  {
185  if (i%2)
186  std::swap(permutation[c[i]], permutation[i]);
187  else
188  std::swap(permutation[0], permutation[i]);
189  run_test();
190 
191  ++c[i];
192  i = 0; // Yeah, this runs in factorial time
193  }
194  else
195  c[i] = 0;
196  }
197  }
198 #endif
199 };
200 
dof_id_type n_elem(const MeshBase::const_element_iterator &begin, const MeshBase::const_element_iterator &end)
Count up the number of elements of a specific type (as defined by an iterator range).
Definition: mesh_tools.C:969
void iota(ForwardIter first, ForwardIter last, T value)
Utility::iota was created back when std::iota was just an SGI STL extension.
Definition: utility.h:229
std::size_t testPermutedHole(const std::vector< std::size_t > &permutation)
CPPUNIT_TEST_SUITE_REGISTRATION(LibMeshNetgenTest)