libMesh
all_second_order.C
Go to the documentation of this file.
1 // libMesh includes
2 #include <libmesh/libmesh.h>
3 #include <libmesh/distributed_mesh.h>
4 #include <libmesh/replicated_mesh.h>
5 #include <libmesh/mesh_generation.h>
6 #include <libmesh/mesh.h>
7 #include <libmesh/point.h>
8 #include <libmesh/elem.h>
9 
10 // cppunit includes
11 #include "test_comm.h"
12 #include "libmesh_cppunit.h"
13 
14 using namespace libMesh;
15 
16 class AllSecondOrderTest : public CppUnit::TestCase
17 {
18 public:
19  LIBMESH_CPPUNIT_TEST_SUITE( AllSecondOrderTest );
20 
21  CPPUNIT_TEST( allSecondOrder );
22  CPPUNIT_TEST( allSecondOrderRange );
23  CPPUNIT_TEST( allSecondOrderDoNothing );
24  CPPUNIT_TEST( allSecondOrderMixed );
25  CPPUNIT_TEST( allSecondOrderMixedFixing );
26  CPPUNIT_TEST( allSecondOrderMixedFixing3D );
27 
28  CPPUNIT_TEST( allCompleteOrder );
29  CPPUNIT_TEST( allCompleteOrderRange );
30  CPPUNIT_TEST( allCompleteOrderDoNothing );
31  CPPUNIT_TEST( allCompleteOrderMixed );
32  CPPUNIT_TEST( allCompleteOrderMixedFixing );
33  CPPUNIT_TEST( allCompleteOrderMixedFixing3D );
34 
35  CPPUNIT_TEST_SUITE_END();
36 
37 public:
38  void setUp() {}
39 
40  void tearDown() {}
41 
43  {
44  LOG_UNIT_TEST;
45 
46  DistributedMesh mesh(*TestCommWorld, /*dim=*/2);
47 
49 
51 
53  }
54 
56  {
58 
59  // Construct a single-element Quad4 mesh
60  MeshTools::Generation::build_square(mesh, /*nx=*/1, /*ny=*/1);
61 
62  // Add extra nodes above the four original nodes
63  Point z_trans(0,0,1);
64  for (dof_id_type n=0; n<4; ++n)
65  mesh.add_point(mesh.point(n) + z_trans, /*id=*/4+n, /*proc_id=*/0);
66 
67  // Construct Edge2 elements attached to Quad4 at individual points
68  // and in subdomain 1.
69  for (dof_id_type n=0; n<4; ++n)
70  {
71  Elem * elem = mesh.add_elem(Elem::build(EDGE2));
72  elem->set_node(0, mesh.node_ptr(n));
73  elem->set_node(1, mesh.node_ptr(n+4));
74  elem->subdomain_id() = 1;
75  }
76 
77  // Convert only Edge2 elements (all elements in subdomain 1) to
78  // SECOND-order.
80  /*full_ordered=*/true);
81 
82  // Make sure we still have the expected total number of elements
83  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(5), mesh.n_elem());
84 
85  // Make sure we added the right number of nodes
86  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12), mesh.n_nodes());
87 
88  // Make sure that the type of the Quad4 is unchanged
89  CPPUNIT_ASSERT_EQUAL(QUAD4, mesh.elem_ptr(0)->type());
90 
91  // Make sure that the other elements are now Edge3s
92  for (dof_id_type e=1; e<5; ++e)
93  CPPUNIT_ASSERT_EQUAL(EDGE3, mesh.elem_ptr(e)->type());
94  }
95 
97  {
98  DistributedMesh mesh(*TestCommWorld, /*dim=*/2);
99 
101 
103  /*nx=*/2, /*ny=*/2,
104  /*xmin=*/0., /*xmax=*/1.,
105  /*ymin=*/0., /*ymax=*/1.,
106  QUAD9);
107 
108  // Test that all_second_order_range() correctly "does nothing" in
109  // parallel when passed ranges of local elements. Here we should
110  // hit one of the "early return" cases for this function.
111  mesh.all_second_order_range(mesh.active_local_element_ptr_range(),
112  /*full_ordered=*/true);
113 
114  // Make sure we still have the same number of elements
115  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(4), mesh.n_elem());
116 
117  // Make sure we still have the same number of nodes
118  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(25), mesh.n_nodes());
119  }
120 
122  {
124 
125  // Construct a single-element Quad9 mesh
127  /*nx=*/1, /*ny=*/1,
128  /*xmin=*/0., /*xmax=*/1.,
129  /*ymin=*/0., /*ymax=*/1.,
130  /*elem_type=*/QUAD9);
131 
132  // Pointer to the single Elem
133  const Elem * elem = mesh.elem_ptr(0);
134 
135  // Amount to offset the indices of newly-added nodes by
136  const unsigned int node_offset = elem->n_nodes();
137 
138  // Add an extra node above each of the original vertices
139  for (dof_id_type n=0; n<elem->n_vertices(); ++n)
140  mesh.add_point(mesh.point(n) + Point(0,0,1), /*id=*/node_offset + n, /*proc_id=*/0);
141 
142  // Construct Edge2 elements and attach to each vertex of Quad9
143  for (dof_id_type n=0; n<elem->n_vertices(); ++n)
144  {
145  Elem * elem = mesh.add_elem(Elem::build(EDGE2));
146  elem->set_node(0, mesh.node_ptr(n));
147  elem->set_node(1, mesh.node_ptr(node_offset + n));
148  }
149 
150  // Convert all elements to SECOND-order, automatically skipping those that are
151  // already SECOND-order.
152  mesh.all_second_order_range(mesh.element_ptr_range(), /*full_ordered=*/true);
153 
154  // Make sure we still have the expected total number of elements
155  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(5), mesh.n_elem());
156 
157  // Make sure we have the correct number of nodes, 9+4+4=17
158  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(17), mesh.n_nodes());
159 
160  // Make sure that the type of the original Elem is unchanged
161  CPPUNIT_ASSERT_EQUAL(QUAD9, elem->type());
162 
163  // Make sure that the other elements are now Edge3s
164  for (dof_id_type e=1; e<5; ++e)
165  CPPUNIT_ASSERT_EQUAL(EDGE3, mesh.elem_ptr(e)->type());
166  }
167 
168  template <typename ConversionFunc>
170  ConversionFunc & conv,
171  dof_id_type expected_n_elem,
172  dof_id_type expected_n_nodes,
173  ElemType expected_type)
174  {
175  // Convert elements to higher-order, but do so a few at a time,
176  // leaving a broken mesh after initial conversions to see if it
177  // will be properly fixed by subsequent conversions.
178 
179  // Keep element ids from being renumbered (DistributedMesh will do
180  // this to get contiguous ranges) so we don't miss any elements
181  // when we're making our ranges by id.
182  mesh.allow_renumbering(false);
183 
184  // This test loop is O(N^2), because conversions can invalidate
185  // iterators so we have to start over each time, but N is like 27
186  // so we're okay.
187  for (dof_id_type start_elem_id : make_range(mesh.max_elem_id()))
188  {
189  auto range_start = mesh.elements_begin();
190  const auto end = mesh.elements_end();
191  while (range_start != end && (*range_start)->id() < start_elem_id)
192  ++range_start;
193  auto range_end = range_start;
194  while (range_end != end && (*range_end)->id() < start_elem_id+1+start_elem_id%2)
195  ++range_end;
196 
197  conv({range_start, range_end});
198  }
199 
200  // Make sure we still have the expected total number of elements
201  CPPUNIT_ASSERT_EQUAL(expected_n_elem, mesh.n_elem());
202 
203  // Make sure we have the correct number of nodes, 7*7
204  CPPUNIT_ASSERT_EQUAL(expected_n_nodes, mesh.n_nodes());
205 
206  // Make sure that the elements are now upgraded
207  for (const auto & elem : mesh.element_ptr_range())
208  CPPUNIT_ASSERT_EQUAL(expected_type, elem->type());
209  }
210 
212  {
214 
215  // Disallow renumbering so we're doing the same thing on any
216  // distributed mesh partitioning
217  mesh.allow_renumbering(false);
218 
219  // Construct a multi-element Quad4 mesh
221  /*nx=*/3, /*ny=*/3,
222  /*xmin=*/0., /*xmax=*/1.,
223  /*ymin=*/0., /*ymax=*/1.,
224  /*elem_type=*/QUAD4);
225 
226  auto conversion = [&mesh](const SimpleRange<MeshBase::element_iterator> & range) {
227  mesh.all_second_order_range(range, /*full_ordered=*/true);
228  };
229 
230  MixedFixingImpl(mesh, conversion, 3*3, 7*7, QUAD9);
231  }
232 
234  {
236 
237  // Construct a multi-element Hex8 mesh
239  /*nx=*/3, /*ny=*/3, /*nz=*/3,
240  /*xmin=*/0., /*xmax=*/1.,
241  /*ymin=*/0., /*ymax=*/1.,
242  /*zmin=*/0., /*zmax=*/1.,
243  /*elem_type=*/HEX8);
244 
245  auto conversion = [&mesh](const SimpleRange<MeshBase::element_iterator> & range) {
246  mesh.all_second_order_range(range, /*full_ordered=*/true);
247  };
248 
249  MixedFixingImpl(mesh, conversion, 3*3*3, 7*7*7, HEX27);
250  }
251 
252 
254  {
255  LOG_UNIT_TEST;
256 
257  DistributedMesh mesh(*TestCommWorld, /*dim=*/2);
258 
260 
262 
264  }
265 
267  {
269 
270  // Construct a single-element Quad4 mesh
271  MeshTools::Generation::build_square(mesh, /*nx=*/1, /*ny=*/1);
272 
273  // Add extra nodes above the four original nodes
274  Point z_trans(0,0,1);
275  for (dof_id_type n=0; n<4; ++n)
276  mesh.add_point(mesh.point(n) + z_trans, /*id=*/4+n, /*proc_id=*/0);
277 
278  // Construct Edge2 elements attached to Quad4 at individual points
279  // and in subdomain 1.
280  for (dof_id_type n=0; n<4; ++n)
281  {
282  Elem * elem = mesh.add_elem(Elem::build(EDGE2));
283  elem->set_node(0, mesh.node_ptr(n));
284  elem->set_node(1, mesh.node_ptr(n+4));
285  elem->subdomain_id() = 1;
286  }
287 
288  // Convert only Edge2 elements (all elements in subdomain 1) to
289  // higher-order.
291 
292  // Make sure we still have the expected total number of elements
293  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(5), mesh.n_elem());
294 
295  // Make sure we added the right number of nodes
296  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(12), mesh.n_nodes());
297 
298  // Make sure that the type of the Quad4 is unchanged
299  CPPUNIT_ASSERT_EQUAL(QUAD4, mesh.elem_ptr(0)->type());
300 
301  // Make sure that the other elements are now Edge3s
302  for (dof_id_type e=1; e<5; ++e)
303  CPPUNIT_ASSERT_EQUAL(EDGE3, mesh.elem_ptr(e)->type());
304  }
305 
307  {
308  DistributedMesh mesh(*TestCommWorld, /*dim=*/2);
309 
311 
313  /*nx=*/2, /*ny=*/2,
314  /*xmin=*/0., /*xmax=*/1.,
315  /*ymin=*/0., /*ymax=*/1.,
316  QUAD9);
317 
318  // Test that all_complete_order_range() correctly "does nothing" in
319  // parallel when passed ranges of local elements. Here we should
320  // hit one of the "early return" cases for this function.
321  mesh.all_complete_order_range(mesh.active_local_element_ptr_range());
322 
323  // Make sure we still have the same number of elements
324  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(4), mesh.n_elem());
325 
326  // Make sure we still have the same number of nodes
327  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(25), mesh.n_nodes());
328  }
329 
331  {
333 
334  // Construct a single-element Quad9 mesh
336  /*nx=*/1, /*ny=*/1,
337  /*xmin=*/0., /*xmax=*/1.,
338  /*ymin=*/0., /*ymax=*/1.,
339  /*elem_type=*/QUAD9);
340 
341  // Pointer to the single Elem
342  const Elem * elem = mesh.elem_ptr(0);
343 
344  // Amount to offset the indices of newly-added nodes by
345  const unsigned int node_offset = elem->n_nodes();
346 
347  // Add an extra node above each of the original vertices
348  for (dof_id_type n=0; n<elem->n_vertices(); ++n)
349  mesh.add_point(mesh.point(n) + Point(0,0,1), /*id=*/node_offset + n, /*proc_id=*/0);
350 
351  // Construct Edge2 elements and attach to each vertex of Quad9
352  for (dof_id_type n=0; n<elem->n_vertices(); ++n)
353  {
354  Elem * elem = mesh.add_elem(Elem::build(EDGE2));
355  elem->set_node(0, mesh.node_ptr(n));
356  elem->set_node(1, mesh.node_ptr(node_offset + n));
357  }
358 
359  // Convert all elements, automatically skipping those that are
360  // already complete-order.
361  mesh.all_complete_order_range(mesh.element_ptr_range());
362 
363  // Make sure we still have the expected total number of elements
364  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(5), mesh.n_elem());
365 
366  // Make sure we have the correct number of nodes, 9+4+4=17
367  CPPUNIT_ASSERT_EQUAL(static_cast<dof_id_type>(17), mesh.n_nodes());
368 
369  // Make sure that the type of the original Elem is unchanged
370  CPPUNIT_ASSERT_EQUAL(QUAD9, elem->type());
371 
372  // Make sure that the other elements are now Edge3s
373  for (dof_id_type e=1; e<5; ++e)
374  CPPUNIT_ASSERT_EQUAL(EDGE3, mesh.elem_ptr(e)->type());
375  }
376 
377 
379  {
381 
382  // Construct a multi-element Tri3 mesh
384  /*nx=*/3, /*ny=*/3,
385  /*xmin=*/0., /*xmax=*/1.,
386  /*ymin=*/0., /*ymax=*/1.,
387  /*elem_type=*/TRI3);
388 
389  auto conversion = [&mesh](const SimpleRange<MeshBase::element_iterator> & range) {
391  };
392 
393  MixedFixingImpl(mesh, conversion, 3*3*2, 7*7+3*3*2, TRI7);
394  }
395 
397  {
399 
400  // Construct a multi-element Prism6 mesh
402  /*nx=*/3, /*ny=*/3, /*nz=*/3,
403  /*xmin=*/0., /*xmax=*/1.,
404  /*ymin=*/0., /*ymax=*/1.,
405  /*zmin=*/0., /*zmax=*/1.,
406  /*elem_type=*/PRISM6);
407 
408  auto conversion = [&mesh](const SimpleRange<MeshBase::element_iterator> & range) {
410  };
411 
412  MixedFixingImpl(mesh, conversion, 3*3*3*2, 7*7*7+3*3*2*7, PRISM21);
413  }
414 
415 
416 };
417 
418 
ElemType
Defines an enum for geometric element types.
The SimpleRange templated class is intended to make it easy to construct ranges from pairs of iterato...
Definition: simple_range.h:36
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
virtual Node *& set_node(const unsigned int i)
Definition: elem.h:2558
void allSecondOrderMixedFixing3D()
virtual void all_second_order_range(const SimpleRange< element_iterator > &range, const bool full_ordered=true)=0
Converts a set of this Mesh&#39;s elements defined by range from FIRST order to SECOND order...
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:1196
libMesh::Parallel::Communicator * TestCommWorld
Definition: driver.C:171
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
MeshBase & mesh
static void MixedFixingImpl(MeshBase &mesh, ConversionFunc &conv, dof_id_type expected_n_elem, dof_id_type expected_n_nodes, ElemType expected_type)
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.
CPPUNIT_TEST_SUITE_REGISTRATION(AllSecondOrderTest)
The libMesh namespace provides an interface to certain functionality in the library.
virtual Node * add_point(const Point &p, const dof_id_type id=DofObject::invalid_id, const processor_id_type proc_id=DofObject::invalid_processor_id)=0
Add a new Node at Point p to the end of the vertex array, with processor_id procid.
This is the MeshBase class.
Definition: mesh_base.h:75
virtual void all_complete_order_range(const SimpleRange< element_iterator > &range)=0
Converts a set of elements in this (conforming, non-refined) mesh into "complete" order elements...
void allow_remote_element_removal(bool allow)
If false is passed in then this mesh will no longer have remote elements deleted when being prepared ...
Definition: mesh_base.h:1212
virtual unsigned int n_nodes() const =0
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition: elem.C:444
virtual dof_id_type max_elem_id() const =0
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
virtual const Elem * elem_ptr(const dof_id_type i) const =0
void allCompleteOrderMixedFixing3D()
void allCompleteOrderMixedFixing()
virtual unsigned int n_vertices() const =0
subdomain_id_type subdomain_id() const
Definition: elem.h:2582
virtual void all_complete_order()
Calls the range-based version of this function with a range consisting of all elements in the mesh...
Definition: mesh_base.C:1613
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:140
void all_second_order(const bool full_ordered=true)
Calls the range-based version of this function with a range consisting of all elements in the mesh...
Definition: mesh_base.C:1608
unsigned int level ElemType type std::set< subdomain_id_type > ss processor_id_type pid unsigned int level std::set< subdomain_id_type > virtual ss SimpleRange< element_iterator > active_subdomain_elements_ptr_range(subdomain_id_type sid)=0
virtual const Point & point(const dof_id_type i) const =0
virtual dof_id_type n_elem() const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition: mesh.h:50
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
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.
virtual dof_id_type n_nodes() const =0
uint8_t dof_id_type
Definition: id_types.h:67