libMesh
Loading...
Searching...
No Matches
fe_gll_collocation_test.C
Go to the documentation of this file.
1// A nodal basis whose interpolation points are the points of a quadrature rule is
2// collocated with that rule. Each shape function is one at its own point and zero at the
3// others, so the matrix of shape function values at the quadrature points is the identity.
4// The mass matrix assembled with the rule is then diagonal. This holds for any mapping and
5// element shape, because the Jacobian only scales the diagonal entries.
6//
7// The basis reads its points from QGaussLobatto, so the property holds exactly. These tests
8// compare shape function values and off-diagonal mass matrix entries against 1 and 0
9// without a tolerance.
10
11#include <libmesh/elem.h>
12#include <libmesh/enum_fe_family.h>
13#include <libmesh/enum_order.h>
14#include <libmesh/fe_base.h>
15#include <libmesh/fe_type.h>
16#include <libmesh/int_range.h>
17#include <libmesh/mesh.h>
18#include <libmesh/mesh_generation.h>
19#include <libmesh/node.h>
20#include <libmesh/parallel_implementation.h>
21#include <libmesh/quadrature.h>
22
23#include "test_comm.h"
24#include "libmesh_cppunit.h"
25
26#include <cmath>
27#include <memory>
28#include <vector>
29
30using namespace libMesh;
31
32template <ElemType elem_type, Order order>
33class FEGLLCollocationTest : public CppUnit::TestCase
34{
35protected:
36 std::unique_ptr<Mesh> _mesh;
37 std::string libmesh_suite_name;
38
39public:
40 void setUp()
41 {
42 _mesh = std::make_unique<Mesh>(*TestCommWorld);
43
44 const unsigned int dim = Elem::type_to_dim_map[elem_type];
45
46 if (dim == 1)
47 MeshTools::Generation::build_line(*_mesh, 2, 0., 1., elem_type);
48 else if (dim == 2)
49 MeshTools::Generation::build_square(*_mesh, 2, 2, 0., 1., 0., 1., elem_type);
50 else
51 MeshTools::Generation::build_cube(*_mesh, 2, 2, 2, 0., 1., 0., 1., 0., 1., elem_type);
52
53 // Shear the mesh so that the mapping to each element has off-diagonal Jacobian terms
54 for (auto * node : _mesh->node_ptr_range())
55 {
56 Node & p = *node;
57 const Real y = (LIBMESH_DIM > 1) ? p(1) : 0.;
58 const Real z = (LIBMESH_DIM > 2) ? p(2) : 0.;
59
60 p(0) += 0.3 * y + 0.17 * z;
61 if (LIBMESH_DIM > 1)
62 p(1) += 0.23 * z;
63 }
64 }
65
66 void tearDown() { _mesh.reset(); }
67
69 std::unique_ptr<QBase> collocated_rule(const FEType & fe_type, const unsigned int dim)
70 {
71 return fe_type.default_quadrature_rule(dim);
72 }
73
75 {
76 LOG_UNIT_TEST;
77
78 const FEType fe_type(order, L2_LAGRANGE_GLL);
79 const unsigned int dim = Elem::type_to_dim_map[elem_type];
80
81 std::unique_ptr<FEBase> fe = FEBase::build(dim, fe_type);
82 std::unique_ptr<QBase> qrule = collocated_rule(fe_type, dim);
83 fe->attach_quadrature_rule(qrule.get());
84
85 // Request phi before reinit so that reinit computes it
86 const std::vector<std::vector<Real>> & phi = fe->get_phi();
87
88 unsigned int n_elem = 0;
89
90 for (const auto * elem : _mesh->active_local_element_ptr_range())
91 {
92 fe->reinit(elem);
93
94 // The collocated rule has one point per degree of freedom
95 CPPUNIT_ASSERT_EQUAL(phi.size(), std::size_t(qrule->n_points()));
96
97 for (const auto i : index_range(phi))
98 for (const auto q : index_range(phi[i]))
99 CPPUNIT_ASSERT_EQUAL((i == q) ? Real(1) : Real(0), phi[i][q]);
100
101 ++n_elem;
102 }
103
104 _mesh->comm().sum(n_elem);
105 CPPUNIT_ASSERT(n_elem > 0);
106 }
107
109 {
110 LOG_UNIT_TEST;
111
112 const FEType fe_type(order, L2_LAGRANGE_GLL);
113 const unsigned int dim = Elem::type_to_dim_map[elem_type];
114
115 std::unique_ptr<FEBase> fe = FEBase::build(dim, fe_type);
116 std::unique_ptr<QBase> qrule = collocated_rule(fe_type, dim);
117 fe->attach_quadrature_rule(qrule.get());
118
119 const std::vector<std::vector<Real>> & phi = fe->get_phi();
120 const std::vector<Real> & JxW = fe->get_JxW();
121
122 for (const auto * elem : _mesh->active_local_element_ptr_range())
123 {
124 fe->reinit(elem);
125
126 const std::size_t n_dofs = phi.size();
127
128 for (const auto i : make_range(n_dofs))
129 for (const auto j : make_range(n_dofs))
130 {
131 Real m = 0.;
132 for (const auto q : index_range(JxW))
133 m += JxW[q] * phi[i][q] * phi[j][q];
134
135 if (i == j)
136 {
137 // Each diagonal entry equals JxW at its own point, which is positive on
138 // a valid element
139 CPPUNIT_ASSERT(m > 0.);
140 LIBMESH_ASSERT_FP_EQUAL(JxW[i], m, TOLERANCE*TOLERANCE);
141 }
142 else
143 CPPUNIT_ASSERT_EQUAL(Real(0), m);
144 }
145 }
146 }
147};
148
149#define INSTANTIATE_FEGLLCOLLOCATIONTEST(elemtype, order) \
150 class FEGLLCollocationTest_##order##_##elemtype : \
151 public FEGLLCollocationTest<elemtype, order> { \
152 public: \
153 FEGLLCollocationTest_##order##_##elemtype() : \
154 FEGLLCollocationTest<elemtype, order>() { \
155 if (unitlog->summarized_logs_enabled()) \
156 this->libmesh_suite_name = "FEGLLCollocationTest"; \
157 else \
158 this->libmesh_suite_name = \
159 "FEGLLCollocationTest_" #order "_" #elemtype; \
160 } \
161 CPPUNIT_TEST_SUITE( FEGLLCollocationTest_##order##_##elemtype ); \
162 CPPUNIT_TEST( testShapesAreIdentity ); \
163 CPPUNIT_TEST( testMassMatrixIsDiagonal ); \
164 CPPUNIT_TEST_SUITE_END(); \
165 }; \
166 \
167 CPPUNIT_TEST_SUITE_REGISTRATION( FEGLLCollocationTest_##order##_##elemtype )
168
172
173#if LIBMESH_DIM > 1
178#endif
179
180#if LIBMESH_DIM > 2
184#endif
unsigned int dim
std::unique_ptr< Mesh > _mesh
std::unique_ptr< QBase > collocated_rule(const FEType &fe_type, const unsigned int dim)
The family's default quadrature rule, which is collocated with the basis.
static const unsigned int type_to_dim_map[INVALID_ELEM]
This array maps the integer representation of the ElemType enum to the geometric dimension of the ele...
Definition elem.h:649
static std::unique_ptr< FEGenericBase > build(const unsigned int dim, const FEType &type)
Builds a specific finite element type.
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition fe_type.h:197
std::unique_ptr< QBase > default_quadrature_rule(const unsigned int dim, const int extraorder=0) const
Definition fe_type.C:35
A Node is like a Point, but with more information.
Definition node.h:55
Communicator * TestCommWorld
INSTANTIATE_FEGLLCOLLOCATIONTEST(EDGE2, FIRST)
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_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.
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.
auto index_range(const T &sizable)
Helper function that returns an IntRange<std::size_t> representing all the indices of the passed-in v...
Definition int_range.h:153
static constexpr Real TOLERANCE
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
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