Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 :
4 : // This library is free software; you can redistribute it and/or
5 : // modify it under the terms of the GNU Lesser General Public
6 : // License as published by the Free Software Foundation; either
7 : // version 2.1 of the License, or (at your option) any later version.
8 :
9 : // This library is distributed in the hope that it will be useful,
10 : // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 : // Lesser General Public License for more details.
13 :
14 : // You should have received a copy of the GNU Lesser General Public
15 : // License along with this library; if not, write to the Free Software
16 : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 :
18 :
19 :
20 : // Local includes
21 : #include "libmesh/elem.h"
22 : #include "libmesh/enum_to_string.h"
23 : #include "libmesh/fe.h"
24 : #include "libmesh/fe_interface.h"
25 : #include "libmesh/fe_lagrange_gll_shape_1D.h"
26 : #include "libmesh/fe_macro.h"
27 :
28 :
29 : namespace libMesh
30 : {
31 :
32 : /**
33 : * \returns The number of degrees of freedom of the L2_LAGRANGE_GLL basis of order \p o on
34 : * an element of type \p t.
35 : *
36 : * The basis is a tensor product of one-dimensional bases, so it is defined only on tensor
37 : * product element types, where it has \f$(p+1)^d\f$ degrees of freedom. All of them belong
38 : * to the element, so the count doesn't depend on the number of nodes, and every supported
39 : * order works on a first order element.
40 : */
41 648274 : unsigned int l2_lagrange_gll_n_dofs(const ElemType t, const Order o)
42 : {
43 56146 : libmesh_assert_greater (o, 0);
44 :
45 648274 : const unsigned int n = static_cast<unsigned int>(o) + 1;
46 :
47 648274 : libmesh_error_msg_if(n > fe_lagrange_gll_max_points_1D,
48 : "The L2_LAGRANGE_GLL basis of order " << o << " needs " << n
49 : << " Gauss-Lobatto points, but QGaussLobatto tabulates at most "
50 : << fe_lagrange_gll_max_points_1D << ".");
51 :
52 648274 : switch (t)
53 : {
54 0 : case NODEELEM:
55 0 : return 1;
56 :
57 23400 : case EDGE2:
58 : case EDGE3:
59 : case EDGE4:
60 23400 : return n;
61 :
62 83452 : case QUAD4:
63 : case QUADSHELL4:
64 : case QUAD8:
65 : case QUADSHELL8:
66 : case QUAD9:
67 : case QUADSHELL9:
68 83452 : return n*n;
69 :
70 541422 : case HEX8:
71 : case HEX20:
72 : case HEX27:
73 541422 : return n*n*n;
74 :
75 0 : case INVALID_ELEM:
76 0 : return 0;
77 :
78 0 : default:
79 0 : libmesh_error_msg("The L2_LAGRANGE_GLL basis is a tensor product and is not defined on "
80 : << Utility::enum_to_string(t) << ".");
81 : }
82 : }
83 :
84 :
85 648274 : unsigned int l2_lagrange_gll_n_dofs(const Elem * e, const Order o)
86 : {
87 56146 : libmesh_assert(e);
88 648274 : return l2_lagrange_gll_n_dofs(e->type(), o);
89 : }
90 :
91 : /**
92 : * Evaluates the solution at the nodes of \p elem, for output formats that write nodal
93 : * values.
94 : *
95 : * The interpolation points coincide with the element nodes only at orders one and two, so
96 : * the solution is evaluated through the shape functions at every order.
97 : */
98 0 : void l2_lagrange_gll_nodal_soln(const Elem * elem,
99 : const Order order,
100 : const std::vector<Number> & elem_soln,
101 : std::vector<Number> & nodal_soln,
102 : const bool add_p_level)
103 : {
104 0 : const unsigned int n_nodes = elem->n_nodes();
105 :
106 0 : nodal_soln.resize(n_nodes);
107 :
108 0 : const FEType fe_type(order, L2_LAGRANGE_GLL);
109 :
110 : const unsigned int n_sf =
111 0 : FEInterface::n_shape_functions(fe_type, elem, add_p_level);
112 :
113 0 : std::vector<Point> refspace_nodes;
114 0 : FEBase::get_refspace_nodes(elem->type(), refspace_nodes);
115 0 : libmesh_assert_equal_to (refspace_nodes.size(), n_nodes);
116 0 : libmesh_assert_equal_to (elem_soln.size(), n_sf);
117 :
118 0 : std::fill(nodal_soln.begin(), nodal_soln.end(), 0);
119 :
120 0 : for (const auto n : make_range(n_nodes))
121 0 : for (const auto i : make_range(n_sf))
122 0 : nodal_soln[n] += elem_soln[i] *
123 0 : FEInterface::shape(fe_type, elem, i, refspace_nodes[n], add_p_level);
124 0 : }
125 :
126 0 : LIBMESH_FE_NODAL_SOLN(L2_LAGRANGE_GLL, l2_lagrange_gll_nodal_soln)
127 0 : LIBMESH_FE_SIDE_NODAL_SOLN(L2_LAGRANGE_GLL)
128 :
129 :
130 : // Every degree of freedom of this basis belongs to the element
131 0 : template <> unsigned int FE<0,L2_LAGRANGE_GLL>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_gll_n_dofs(t, o); }
132 0 : template <> unsigned int FE<1,L2_LAGRANGE_GLL>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_gll_n_dofs(t, o); }
133 0 : template <> unsigned int FE<2,L2_LAGRANGE_GLL>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_gll_n_dofs(t, o); }
134 0 : template <> unsigned int FE<3,L2_LAGRANGE_GLL>::n_dofs(const ElemType t, const Order o) { return l2_lagrange_gll_n_dofs(t, o); }
135 :
136 0 : template <> unsigned int FE<0,L2_LAGRANGE_GLL>::n_dofs(const Elem * e, const Order o) { return l2_lagrange_gll_n_dofs(e, o); }
137 12012 : template <> unsigned int FE<1,L2_LAGRANGE_GLL>::n_dofs(const Elem * e, const Order o) { return l2_lagrange_gll_n_dofs(e, o); }
138 72064 : template <> unsigned int FE<2,L2_LAGRANGE_GLL>::n_dofs(const Elem * e, const Order o) { return l2_lagrange_gll_n_dofs(e, o); }
139 530034 : template <> unsigned int FE<3,L2_LAGRANGE_GLL>::n_dofs(const Elem * e, const Order o) { return l2_lagrange_gll_n_dofs(e, o); }
140 :
141 0 : template <> unsigned int FE<0,L2_LAGRANGE_GLL>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
142 21528 : template <> unsigned int FE<1,L2_LAGRANGE_GLL>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
143 50232 : template <> unsigned int FE<2,L2_LAGRANGE_GLL>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
144 131560 : template <> unsigned int FE<3,L2_LAGRANGE_GLL>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
145 :
146 0 : template <> unsigned int FE<0,L2_LAGRANGE_GLL>::n_dofs_at_node(const Elem &, const Order, const unsigned int) { return 0; }
147 14820 : template <> unsigned int FE<1,L2_LAGRANGE_GLL>::n_dofs_at_node(const Elem &, const Order, const unsigned int) { return 0; }
148 28860 : template <> unsigned int FE<2,L2_LAGRANGE_GLL>::n_dofs_at_node(const Elem &, const Order, const unsigned int) { return 0; }
149 68484 : template <> unsigned int FE<3,L2_LAGRANGE_GLL>::n_dofs_at_node(const Elem &, const Order, const unsigned int) { return 0; }
150 :
151 0 : template <> unsigned int FE<0,L2_LAGRANGE_GLL>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_gll_n_dofs(t, o); }
152 0 : template <> unsigned int FE<1,L2_LAGRANGE_GLL>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_gll_n_dofs(t, o); }
153 0 : template <> unsigned int FE<2,L2_LAGRANGE_GLL>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_gll_n_dofs(t, o); }
154 0 : template <> unsigned int FE<3,L2_LAGRANGE_GLL>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_lagrange_gll_n_dofs(t, o); }
155 :
156 0 : template <> unsigned int FE<0,L2_LAGRANGE_GLL>::n_dofs_per_elem(const Elem & e, const Order o) { return l2_lagrange_gll_n_dofs(&e, o); }
157 11388 : template <> unsigned int FE<1,L2_LAGRANGE_GLL>::n_dofs_per_elem(const Elem & e, const Order o) { return l2_lagrange_gll_n_dofs(&e, o); }
158 11388 : template <> unsigned int FE<2,L2_LAGRANGE_GLL>::n_dofs_per_elem(const Elem & e, const Order o) { return l2_lagrange_gll_n_dofs(&e, o); }
159 11388 : template <> unsigned int FE<3,L2_LAGRANGE_GLL>::n_dofs_per_elem(const Elem & e, const Order o) { return l2_lagrange_gll_n_dofs(&e, o); }
160 :
161 :
162 0 : template <> FEContinuity FE<0,L2_LAGRANGE_GLL>::get_continuity() const { return DISCONTINUOUS; }
163 57396 : template <> FEContinuity FE<1,L2_LAGRANGE_GLL>::get_continuity() const { return DISCONTINUOUS; }
164 57396 : template <> FEContinuity FE<2,L2_LAGRANGE_GLL>::get_continuity() const { return DISCONTINUOUS; }
165 57396 : template <> FEContinuity FE<3,L2_LAGRANGE_GLL>::get_continuity() const { return DISCONTINUOUS; }
166 :
167 : // A nodal basis is not hierarchic
168 0 : template <> bool FE<0,L2_LAGRANGE_GLL>::is_hierarchic() const { return false; }
169 144 : template <> bool FE<1,L2_LAGRANGE_GLL>::is_hierarchic() const { return false; }
170 144 : template <> bool FE<2,L2_LAGRANGE_GLL>::is_hierarchic() const { return false; }
171 144 : template <> bool FE<3,L2_LAGRANGE_GLL>::is_hierarchic() const { return false; }
172 :
173 : // The shape functions are the same on every element of a type
174 0 : template <> bool FE<0,L2_LAGRANGE_GLL>::shapes_need_reinit() const { return false; }
175 2460 : template <> bool FE<1,L2_LAGRANGE_GLL>::shapes_need_reinit() const { return false; }
176 2792 : template <> bool FE<2,L2_LAGRANGE_GLL>::shapes_need_reinit() const { return false; }
177 3126 : template <> bool FE<3,L2_LAGRANGE_GLL>::shapes_need_reinit() const { return false; }
178 :
179 : // This DISCONTINUOUS basis doesn't need hanging node constraints, so these are empty
180 : #ifdef LIBMESH_ENABLE_AMR
181 : template <>
182 0 : void FE<2,L2_LAGRANGE_GLL>::compute_constraints (DofConstraints &,
183 : DofMap &,
184 : const unsigned int,
185 : const Elem *)
186 0 : { }
187 :
188 : template <>
189 0 : void FE<3,L2_LAGRANGE_GLL>::compute_constraints (DofConstraints &,
190 : DofMap &,
191 : const unsigned int,
192 : const Elem *)
193 0 : { }
194 : #endif // LIBMESH_ENABLE_AMR
195 :
196 :
197 : } // namespace libMesh
|