Line data Source code
1 : // The libMesh Finite Element Library.
2 : // Copyright (C) 2002-2025 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_macro.h"
26 :
27 : namespace libMesh
28 : {
29 :
30 : // ------------------------------------------------------------
31 : // Hierarchic-specific implementations
32 :
33 : // Anonymous namespace for local helper functions
34 : namespace {
35 :
36 113899 : void l2_hierarchic_nodal_soln(const Elem * elem,
37 : const Order order,
38 : const std::vector<Number> & elem_soln,
39 : std::vector<Number> & nodal_soln,
40 : const bool add_p_level)
41 : {
42 113899 : const unsigned int n_nodes = elem->n_nodes();
43 :
44 113899 : const ElemType elem_type = elem->type();
45 :
46 113899 : nodal_soln.resize(n_nodes);
47 :
48 123463 : const Order totalorder = order + add_p_level*elem->p_level();
49 :
50 : // FEType object to be passed to various FEInterface functions below.
51 9564 : FEType fe_type(order, L2_HIERARCHIC);
52 :
53 113899 : switch (totalorder)
54 : {
55 : // Constant shape functions
56 0 : case CONSTANT:
57 : {
58 0 : libmesh_assert_equal_to (elem_soln.size(), 1);
59 :
60 0 : std::fill(nodal_soln.begin(), nodal_soln.end(), elem_soln[0]);
61 :
62 0 : return;
63 : }
64 :
65 :
66 : // For other orders do interpolation at the nodes
67 : // explicitly.
68 113899 : default:
69 : {
70 : const unsigned int n_sf =
71 113899 : FEInterface::n_shape_functions(fe_type, elem);
72 :
73 19128 : std::vector<Point> refspace_nodes;
74 113899 : FEBase::get_refspace_nodes(elem_type,refspace_nodes);
75 9564 : libmesh_assert_equal_to (refspace_nodes.size(), n_nodes);
76 9564 : libmesh_assert_equal_to (elem_soln.size(), n_sf);
77 :
78 : // Zero before summation
79 9564 : std::fill(nodal_soln.begin(), nodal_soln.end(), 0);
80 :
81 1143675 : for (unsigned int n=0; n<n_nodes; n++)
82 : // u_i = Sum (alpha_i phi_i)
83 8122216 : for (unsigned int i=0; i<n_sf; i++)
84 7720554 : nodal_soln[n] += elem_soln[i] *
85 7720554 : FEInterface::shape(fe_type, elem, i, refspace_nodes[n]);
86 :
87 9564 : return;
88 : }
89 : }
90 : } // l2_hierarchic_nodal_soln()
91 :
92 :
93 :
94 10966709 : unsigned int l2_hierarchic_n_dofs(const ElemType t, const Order o)
95 : {
96 1129554 : libmesh_assert_greater (o, 0);
97 10966709 : switch (t)
98 : {
99 0 : case NODEELEM:
100 0 : return 1;
101 825 : case EDGE2:
102 : case EDGE3:
103 7425 : return (o+1);
104 26173 : case QUAD4:
105 : case QUADSHELL4:
106 : case QUAD8:
107 : case QUADSHELL8:
108 : case QUAD9:
109 : case QUADSHELL9:
110 209573 : return ((o+1)*(o+1));
111 67057 : case HEX8:
112 : case HEX20:
113 : case HEX27:
114 680272 : return ((o+1)*(o+1)*(o+1));
115 31824 : case PRISM6:
116 : case PRISM15:
117 : case PRISM18:
118 : case PRISM20:
119 : case PRISM21:
120 380070 : return ((o+1)*(o+1)*(o+2)/2);
121 509764 : case TRI3:
122 : case TRI6:
123 : case TRI7:
124 4722240 : return ((o+1)*(o+2)/2);
125 493911 : case TET4:
126 : case TET10:
127 : case TET14:
128 5398712 : return ((o+1)*(o+2)*(o+3)/6);
129 0 : case INVALID_ELEM:
130 0 : return 0;
131 0 : default:
132 0 : libmesh_error_msg("ERROR: Invalid ElemType " << Utility::enum_to_string(t) << " selected for L2_HIERARCHIC FE family!");
133 : }
134 : } // l2_hierarchic_n_dofs()
135 :
136 :
137 :
138 10075921 : unsigned int l2_hierarchic_n_dofs(const Elem * e, const Order o)
139 : {
140 1129554 : libmesh_assert(e);
141 10966709 : return l2_hierarchic_n_dofs(e->type(), o);
142 : }
143 :
144 :
145 : } // anonymous namespace
146 :
147 :
148 : // Instantiate (side_) nodal_soln() function for every dimension
149 113899 : LIBMESH_FE_NODAL_SOLN(L2_HIERARCHIC, l2_hierarchic_nodal_soln)
150 0 : LIBMESH_FE_SIDE_NODAL_SOLN(L2_HIERARCHIC)
151 :
152 :
153 : // Full specialization of n_dofs() function for every dimension
154 0 : template <> unsigned int FE<0,L2_HIERARCHIC>::n_dofs(const ElemType t, const Order o) { return l2_hierarchic_n_dofs(t, o); }
155 0 : template <> unsigned int FE<1,L2_HIERARCHIC>::n_dofs(const ElemType t, const Order o) { return l2_hierarchic_n_dofs(t, o); }
156 0 : template <> unsigned int FE<2,L2_HIERARCHIC>::n_dofs(const ElemType t, const Order o) { return l2_hierarchic_n_dofs(t, o); }
157 0 : template <> unsigned int FE<3,L2_HIERARCHIC>::n_dofs(const ElemType t, const Order o) { return l2_hierarchic_n_dofs(t, o); }
158 :
159 0 : template <> unsigned int FE<0,L2_HIERARCHIC>::n_dofs(const Elem * e, const Order o) { return l2_hierarchic_n_dofs(e, o); }
160 4140 : template <> unsigned int FE<1,L2_HIERARCHIC>::n_dofs(const Elem * e, const Order o) { return l2_hierarchic_n_dofs(e, o); }
161 3636948 : template <> unsigned int FE<2,L2_HIERARCHIC>::n_dofs(const Elem * e, const Order o) { return l2_hierarchic_n_dofs(e, o); }
162 4911494 : template <> unsigned int FE<3,L2_HIERARCHIC>::n_dofs(const Elem * e, const Order o) { return l2_hierarchic_n_dofs(e, o); }
163 :
164 : // Full specialization of n_dofs_at_node() function for every dimension.
165 : // Discontinuous L2 elements only have interior nodes
166 0 : template <> unsigned int FE<0,L2_HIERARCHIC>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
167 5382 : template <> unsigned int FE<1,L2_HIERARCHIC>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
168 7553360 : template <> unsigned int FE<2,L2_HIERARCHIC>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
169 11655668 : template <> unsigned int FE<3,L2_HIERARCHIC>::n_dofs_at_node(const ElemType, const Order, const unsigned int) { return 0; }
170 :
171 0 : template <> unsigned int FE<0,L2_HIERARCHIC>::n_dofs_at_node(const Elem &, const Order, const unsigned int) { return 0; }
172 3969 : template <> unsigned int FE<1,L2_HIERARCHIC>::n_dofs_at_node(const Elem &, const Order, const unsigned int) { return 0; }
173 1293155 : template <> unsigned int FE<2,L2_HIERARCHIC>::n_dofs_at_node(const Elem &, const Order, const unsigned int) { return 0; }
174 2845415 : template <> unsigned int FE<3,L2_HIERARCHIC>::n_dofs_at_node(const Elem &, const Order, const unsigned int) { return 0; }
175 :
176 : // Full specialization of n_dofs_per_elem() function for every dimension.
177 0 : template <> unsigned int FE<0,L2_HIERARCHIC>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_hierarchic_n_dofs(t, o); }
178 0 : template <> unsigned int FE<1,L2_HIERARCHIC>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_hierarchic_n_dofs(t, o); }
179 0 : template <> unsigned int FE<2,L2_HIERARCHIC>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_hierarchic_n_dofs(t, o); }
180 0 : template <> unsigned int FE<3,L2_HIERARCHIC>::n_dofs_per_elem(const ElemType t, const Order o) { return l2_hierarchic_n_dofs(t, o); }
181 :
182 0 : template <> unsigned int FE<0,L2_HIERARCHIC>::n_dofs_per_elem(const Elem & e, const Order o) { return l2_hierarchic_n_dofs(&e, o); }
183 3285 : template <> unsigned int FE<1,L2_HIERARCHIC>::n_dofs_per_elem(const Elem & e, const Order o) { return l2_hierarchic_n_dofs(&e, o); }
184 1294865 : template <> unsigned int FE<2,L2_HIERARCHIC>::n_dofs_per_elem(const Elem & e, const Order o) { return l2_hierarchic_n_dofs(&e, o); }
185 1115977 : template <> unsigned int FE<3,L2_HIERARCHIC>::n_dofs_per_elem(const Elem & e, const Order o) { return l2_hierarchic_n_dofs(&e, o); }
186 :
187 : // L2 Hierarchic FEMs are C^0 continuous
188 0 : template <> FEContinuity FE<0,L2_HIERARCHIC>::get_continuity() const { return DISCONTINUOUS; }
189 16575 : template <> FEContinuity FE<1,L2_HIERARCHIC>::get_continuity() const { return DISCONTINUOUS; }
190 44039 : template <> FEContinuity FE<2,L2_HIERARCHIC>::get_continuity() const { return DISCONTINUOUS; }
191 82596 : template <> FEContinuity FE<3,L2_HIERARCHIC>::get_continuity() const { return DISCONTINUOUS; }
192 :
193 : // L2 Hierarchic FEMs are hierarchic (duh!)
194 0 : template <> bool FE<0,L2_HIERARCHIC>::is_hierarchic() const { return true; }
195 60 : template <> bool FE<1,L2_HIERARCHIC>::is_hierarchic() const { return true; }
196 236 : template <> bool FE<2,L2_HIERARCHIC>::is_hierarchic() const { return true; }
197 594 : template <> bool FE<3,L2_HIERARCHIC>::is_hierarchic() const { return true; }
198 :
199 : #ifdef LIBMESH_ENABLE_AMR
200 : // compute_constraints() is a NOOP for DISCONTINUOUS FE's
201 : template <>
202 0 : void FE<2,L2_HIERARCHIC>::compute_constraints (DofConstraints &,
203 : DofMap &,
204 : const unsigned int,
205 : const Elem *)
206 0 : { }
207 :
208 : template <>
209 0 : void FE<3,L2_HIERARCHIC>::compute_constraints (DofConstraints &,
210 : DofMap &,
211 : const unsigned int,
212 : const Elem *)
213 0 : { }
214 : #endif // #ifdef LIBMESH_ENABLE_AMR
215 :
216 : // L2-Hierarchic FEM shapes need reinit
217 0 : template <> bool FE<0,L2_HIERARCHIC>::shapes_need_reinit() const { return true; }
218 720 : template <> bool FE<1,L2_HIERARCHIC>::shapes_need_reinit() const { return true; }
219 2205512 : template <> bool FE<2,L2_HIERARCHIC>::shapes_need_reinit() const { return true; }
220 2353698 : template <> bool FE<3,L2_HIERARCHIC>::shapes_need_reinit() const { return true; }
221 :
222 : } // namespace libMesh
|