libMesh
Loading...
Searching...
No Matches
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
14using namespace libMesh;
15
16class AllSecondOrderTest : public CppUnit::TestCase
17{
18public:
20
27
34
36
37public:
38 void setUp() {}
39
40 void tearDown() {}
41
43 {
44 LOG_UNIT_TEST;
45
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 {
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 {
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 {
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
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 {
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 {
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 {
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
CPPUNIT_TEST_SUITE_REGISTRATION(AllSecondOrderTest)
CPPUNIT_TEST(allCompleteOrder)
CPPUNIT_TEST(allCompleteOrderRange)
CPPUNIT_TEST(allSecondOrderMixed)
CPPUNIT_TEST(allCompleteOrderDoNothing)
CPPUNIT_TEST(allSecondOrderMixedFixing)
CPPUNIT_TEST(allCompleteOrderMixed)
static void MixedFixingImpl(MeshBase &mesh, ConversionFunc &conv, dof_id_type expected_n_elem, dof_id_type expected_n_nodes, ElemType expected_type)
CPPUNIT_TEST(allCompleteOrderMixedFixing3D)
CPPUNIT_TEST(allSecondOrder)
CPPUNIT_TEST(allSecondOrderDoNothing)
LIBMESH_CPPUNIT_TEST_SUITE(AllSecondOrderTest)
CPPUNIT_TEST(allSecondOrderRange)
CPPUNIT_TEST(allSecondOrderMixedFixing3D)
CPPUNIT_TEST(allCompleteOrderMixedFixing)
The DistributedMesh class is derived from the MeshBase class, and is intended to provide identical fu...
This is the base class from which all geometric element types are derived.
Definition elem.h:96
virtual Node *& set_node(const unsigned int i)
Definition elem.h:2567
virtual unsigned int n_vertices() const =0
virtual unsigned int n_nodes() const =0
static std::unique_ptr< Elem > build(const ElemType type, Elem *p=nullptr)
Definition elem.C:442
subdomain_id_type subdomain_id() const
Definition elem.h:2591
virtual ElemType type() const =0
This is the MeshBase class.
Definition mesh_base.h:81
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:1378
virtual const Point & point(const dof_id_type i) const =0
virtual const Node * node_ptr(const dof_id_type i) const =0
virtual dof_id_type n_elem() const =0
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:1355
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:1803
virtual dof_id_type n_nodes() const =0
virtual void all_second_order_range(const SimpleRange< element_iterator > &range, const bool full_ordered=true)=0
Converts a set of this Mesh's elements defined by range from FIRST order to SECOND order.
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.
virtual const Elem * elem_ptr(const dof_id_type i) const =0
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,...
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 dof_id_type max_elem_id() const =0
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:1808
virtual Elem * add_elem(Elem *e)=0
Add elem e to the end of the element array.
The Mesh class is a thin wrapper, around the ReplicatedMesh class by default.
Definition mesh.h:51
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition point.h:40
The ReplicatedMesh class is derived from the MeshBase class, and is used to store identical copies of...
The SimpleRange templated class is intended to make it easy to construct ranges from pairs of iterato...
Communicator * TestCommWorld
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.
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.
The libMesh namespace provides an interface to certain functionality in the library.
ElemType
Defines an enum for geometric element types.
uint8_t dof_id_type
Definition id_types.h:67
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