libMesh
Loading...
Searching...
No Matches
hcurl_fe_transformation.C
Go to the documentation of this file.
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#include "libmesh/hcurl_fe_transformation.h"
19#include "libmesh/fe_interface.h"
20#include "libmesh/int_range.h"
21
22namespace libMesh
23{
24
25template<typename OutputShape>
30
31
32
33template<typename OutputShape>
38
39
40
41template<typename OutputShape>
43{
44 fe.get_fe_map().get_dxidx();
45#ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
47#endif
48}
49
50
51
52template<typename OutputShape>
54 const Elem * const elem,
55 const std::vector<Point> & qp,
57 std::vector<std::vector<OutputShape>> & phi,
58 const bool /*add_p_level*/) const
59{
60 switch (dim)
61 {
62 case 0:
63 case 1:
64 libmesh_error_msg("These element transformations only make sense in 2D and 3D.");
65
66 case 2:
67 {
68 const std::vector<Real> & dxidx_map = fe.get_fe_map().get_dxidx();
69 const std::vector<Real> & dxidy_map = fe.get_fe_map().get_dxidy();
70 const std::vector<Real> & dxidz_map = fe.get_fe_map().get_dxidz();
71
72 const std::vector<Real> & detadx_map = fe.get_fe_map().get_detadx();
73 const std::vector<Real> & detady_map = fe.get_fe_map().get_detady();
74 const std::vector<Real> & detadz_map = fe.get_fe_map().get_detadz();
75
76 // phi = (dx/dxi)^-T * \hat{phi}
77 // In 2D (embedded in 3D):
78 // (dx/dxi)^{-1} = [ dxi/dx dxi/dy dxi/dz
79 // deta/dx deta/dy deta/dz ]
80 //
81 // so: dxi/dx^{-T} * \hat{phi} = [ dxi/dx deta/dx [ \hat{phi}_xi
82 // dxi/dy deta/dy \hat{phi}_eta ]
83 // dxi/dz deta/dz ]
84 //
85 // or in indicial notation: phi_j = xi_{i,j}*\hat{phi}_i
86 for (auto i : index_range(phi))
87 for (auto p : index_range(phi[i]))
88 {
89 // Need to temporarily cache reference shape functions
90 // TODO: PB: Might be worth trying to build phi_ref separately to see
91 // if we can get vectorization
92 // We are computing mapping basis functions, so we explicitly ignore
93 // any non-zero p_level() the Elem might have.
94 OutputShape phi_ref;
95 FEInterface::shape(fe.get_fe_type(), /*extra_order=*/0, elem, i, qp[p], phi_ref);
96
97 phi[i][p](0) = dxidx_map[p]*phi_ref.slice(0) + detadx_map[p]*phi_ref.slice(1);
98
99 phi[i][p](1) = dxidy_map[p]*phi_ref.slice(0) + detady_map[p]*phi_ref.slice(1);
100
101 phi[i][p](2) = dxidz_map[p]*phi_ref.slice(0) + detadz_map[p]*phi_ref.slice(1);
102 }
103
104 break;
105 }
106
107 case 3:
108 {
109 const std::vector<Real> & dxidx_map = fe.get_fe_map().get_dxidx();
110 const std::vector<Real> & dxidy_map = fe.get_fe_map().get_dxidy();
111 const std::vector<Real> & dxidz_map = fe.get_fe_map().get_dxidz();
112
113 const std::vector<Real> & detadx_map = fe.get_fe_map().get_detadx();
114 const std::vector<Real> & detady_map = fe.get_fe_map().get_detady();
115 const std::vector<Real> & detadz_map = fe.get_fe_map().get_detadz();
116
117 const std::vector<Real> & dzetadx_map = fe.get_fe_map().get_dzetadx();
118 const std::vector<Real> & dzetady_map = fe.get_fe_map().get_dzetady();
119 const std::vector<Real> & dzetadz_map = fe.get_fe_map().get_dzetadz();
120
121 // phi = (dx/dxi)^-T * \hat{phi}
122 // In 3D:
123 // dx/dxi^-1 = [ dxi/dx dxi/dy dxi/dz
124 // deta/dx deta/dy deta/dz
125 // dzeta/dx dzeta/dy dzeta/dz]
126 //
127 // so: dxi/dx^-T * \hat{phi} = [ dxi/dx deta/dx dzeta/dx [ \hat{phi}_xi
128 // dxi/dy deta/dy dzeta/dy \hat{phi}_eta
129 // dxi/dz deta/dz dzeta/dz ] \hat{phi}_zeta ]
130 //
131 // or in indicial notation: phi_j = xi_{i,j}*\hat{phi}_i
132 for (auto i : index_range(phi))
133 for (auto p : index_range(phi[i]))
134 {
135 // Need to temporarily cache reference shape functions
136 // TODO: PB: Might be worth trying to build phi_ref separately to see
137 // if we can get vectorization
138 // We are computing mapping basis functions, so we explicitly ignore
139 // any non-zero p_level() the Elem might have.
140 OutputShape phi_ref;
141 FEInterface::shape(fe.get_fe_type(), /*extra_order=*/0, elem, i, qp[p], phi_ref);
142
143 phi[i][p].slice(0) = dxidx_map[p]*phi_ref.slice(0) + detadx_map[p]*phi_ref.slice(1)
144 + dzetadx_map[p]*phi_ref.slice(2);
145
146 phi[i][p].slice(1) = dxidy_map[p]*phi_ref.slice(0) + detady_map[p]*phi_ref.slice(1)
147 + dzetady_map[p]*phi_ref.slice(2);
148
149 phi[i][p].slice(2) = dxidz_map[p]*phi_ref.slice(0) + detadz_map[p]*phi_ref.slice(1)
150 + dzetadz_map[p]*phi_ref.slice(2);
151 }
152 break;
153 }
154
155 default:
156 libmesh_error_msg("Invalid dim = " << dim);
157 } // switch(dim)
158}
159
160template<typename OutputShape>
162 const Elem * const,
163 const std::vector<Point> &,
165 std::vector<std::vector<OutputShape>> & curl_phi) const
166{
167 switch (dim)
168 {
169 case 0:
170 case 1:
171 libmesh_error_msg("These element transformations only make sense in 2D and 3D.");
172
173 case 2:
174 {
175 const std::vector<Real> & dxidx_map = fe.get_fe_map().get_dxidx();
176 const std::vector<Real> & dxidy_map = fe.get_fe_map().get_dxidy();
177 const std::vector<Real> & dxidz_map = fe.get_fe_map().get_dxidz();
178
179 const std::vector<Real> & detadx_map = fe.get_fe_map().get_detadx();
180 const std::vector<Real> & detady_map = fe.get_fe_map().get_detady();
181 const std::vector<Real> & detadz_map = fe.get_fe_map().get_detadz();
182
183 const std::vector<std::vector<OutputShape>> & dphi_dxi = fe.get_dphidxi();
184 const std::vector<std::vector<OutputShape>> & dphi_deta = fe.get_dphideta();
185
186 // In 2D (embedded in 3D): curl(phi)_j = C(j) * curl(\hat{phi}) where C(j)
187 // is the jth column cofactor of (dx/dxi)^{-1} = [ dxi/dx dxi/dy dxi/dz
188 // deta/dx deta/dy deta/dz ]
189 for (auto i : index_range(curl_phi))
190 for (auto p : index_range(curl_phi[i]))
191 {
192 const Real curl_ref = dphi_dxi[i][p].slice(1) - dphi_deta[i][p].slice(0);
193 curl_phi[i][p].slice(0) = curl_ref * (dxidy_map[p]*detadz_map[p] - dxidz_map[p]*detady_map[p]);
194 curl_phi[i][p].slice(1) = curl_ref * -(dxidx_map[p]*detadz_map[p] - dxidz_map[p]*detadx_map[p]);
195 curl_phi[i][p].slice(2) = curl_ref * (dxidx_map[p]*detady_map[p] - dxidy_map[p]*detadx_map[p]);
196 }
197
198 break;
199 }
200
201 case 3:
202 {
203 const std::vector<std::vector<OutputShape>> & dphi_dxi = fe.get_dphidxi();
204 const std::vector<std::vector<OutputShape>> & dphi_deta = fe.get_dphideta();
205 const std::vector<std::vector<OutputShape>> & dphi_dzeta = fe.get_dphidzeta();
206
207 const std::vector<RealGradient> & dxyz_dxi = fe.get_fe_map().get_dxyzdxi();
208 const std::vector<RealGradient> & dxyz_deta = fe.get_fe_map().get_dxyzdeta();
209 const std::vector<RealGradient> & dxyz_dzeta = fe.get_fe_map().get_dxyzdzeta();
210
211 const std::vector<Real> & J = fe.get_fe_map().get_jacobian();
212
213 for (auto i : index_range(curl_phi))
214 for (auto p : index_range(curl_phi[i]))
215 {
216 Real dx_dxi = dxyz_dxi[p](0);
217 Real dx_deta = dxyz_deta[p](0);
218 Real dx_dzeta = dxyz_dzeta[p](0);
219
220 Real dy_dxi = dxyz_dxi[p](1);
221 Real dy_deta = dxyz_deta[p](1);
222 Real dy_dzeta = dxyz_dzeta[p](1);
223
224 Real dz_dxi = dxyz_dxi[p](2);
225 Real dz_deta = dxyz_deta[p](2);
226 Real dz_dzeta = dxyz_dzeta[p](2);
227
228 const Real inv_jac = 1.0/J[p];
229
230 /* In 3D: curl(phi) = J^{-1} dx/dxi * curl(\hat{phi})
231
232 dx/dxi = [ dx/dxi dx/deta dx/dzeta
233 dy/dxi dy/deta dy/dzeta
234 dz/dxi dz/deta dz/dzeta ]
235
236 curl(u) = [ du_z/deta - du_y/dzeta
237 du_x/dzeta - du_z/dxi
238 du_y/dxi - du_x/deta ]
239 */
240 curl_phi[i][p].slice(0) = inv_jac*( dx_dxi*( dphi_deta[i][p].slice(2) -
241 dphi_dzeta[i][p].slice(1) ) +
242 dx_deta*( dphi_dzeta[i][p].slice(0) -
243 dphi_dxi[i][p].slice(2) ) +
244 dx_dzeta*( dphi_dxi[i][p].slice(1) -
245 dphi_deta[i][p].slice(0) ) );
246
247 curl_phi[i][p].slice(1) = inv_jac*( dy_dxi*( dphi_deta[i][p].slice(2) -
248 dphi_dzeta[i][p].slice(1) ) +
249 dy_deta*( dphi_dzeta[i][p].slice(0)-
250 dphi_dxi[i][p].slice(2) ) +
251 dy_dzeta*( dphi_dxi[i][p].slice(1) -
252 dphi_deta[i][p].slice(0) ) );
253
254 curl_phi[i][p].slice(2) = inv_jac*( dz_dxi*( dphi_deta[i][p].slice(2) -
255 dphi_dzeta[i][p].slice(1) ) +
256 dz_deta*( dphi_dzeta[i][p].slice(0) -
257 dphi_dxi[i][p].slice(2) ) +
258 dz_dzeta*( dphi_dxi[i][p].slice(1) -
259 dphi_deta[i][p].slice(0) ) );
260 }
261
262 break;
263 }
264
265 default:
266 libmesh_error_msg("Invalid dim = " << dim);
267 } // switch(dim)
268}
269
270template class LIBMESH_EXPORT HCurlFETransformation<RealGradient>;
271
272template<>
274{
275 libmesh_error_msg("HCurl transformations only make sense for vector-valued elements.");
276}
277
278template<>
280{
281 libmesh_error_msg("HCurl transformations only make sense for vector-valued elements.");
282}
283
284template<>
286{
287 libmesh_error_msg("HCurl transformations only make sense for vector-valued elements.");
288}
289
290template<>
292 const Elem * const,
293 const std::vector<Point> &,
294 const FEGenericBase<Real> &,
295 std::vector<std::vector<Real>> &,
296 bool) const
297{
298 libmesh_error_msg("HCurl transformations only make sense for vector-valued elements.");
299}
300
301template<>
303 const Elem * const,
304 const std::vector<Point> &,
305 const FEGenericBase<Real> &,
306 std::vector<std::vector<Real>> &) const
307{
308 libmesh_error_msg("HCurl transformations only make sense for vector-valued elements.");
309}
310
311
312} // namespace libMesh
unsigned int dim
This is the base class from which all geometric element types are derived.
Definition elem.h:96
FEType get_fe_type() const
const FEMap & get_fe_map() const
This class forms the foundation from which generic finite elements may be derived.
Definition fe_base.h:86
const std::vector< std::vector< OutputShape > > & get_dphidxi() const
Definition fe_base.h:293
const std::vector< std::vector< OutputShape > > & get_dphidzeta() const
Definition fe_base.h:309
const std::vector< std::vector< OutputShape > > & get_dphideta() const
Definition fe_base.h:301
static Real shape(const unsigned int dim, const FEType &fe_t, const ElemType t, const unsigned int i, const Point &p)
const std::vector< Real > & get_dxidz() const
Definition fe_map.h:325
const std::vector< RealGradient > & get_dxyzdeta() const
Definition fe_map.h:247
const std::vector< Real > & get_detadx() const
Definition fe_map.h:333
const std::vector< Real > & get_jacobian() const
Definition fe_map.h:223
const std::vector< Real > & get_dzetady() const
Definition fe_map.h:365
const std::vector< Real > & get_detady() const
Definition fe_map.h:341
const std::vector< Real > & get_dxidx() const
Definition fe_map.h:309
const std::vector< Real > & get_dzetadx() const
Definition fe_map.h:357
const std::vector< RealGradient > & get_dxyzdzeta() const
Definition fe_map.h:255
const std::vector< std::vector< Real > > & get_d2xidxyz2() const
Second derivatives of "xi" reference coordinate wrt physical coordinates.
Definition fe_map.h:381
const std::vector< Real > & get_dxidy() const
Definition fe_map.h:317
const std::vector< RealGradient > & get_dxyzdxi() const
Definition fe_map.h:239
const std::vector< Real > & get_dzetadz() const
Definition fe_map.h:373
const std::vector< Real > & get_detadz() const
Definition fe_map.h:349
This class handles the computation of the shape functions in the physical domain for HCurl conforming...
virtual void init_map_phi(const FEGenericBase< OutputShape > &fe) const override
Pre-requests any necessary data from FEMap.
virtual void map_phi(const unsigned int dim, const Elem *const elem, const std::vector< Point > &qp, const FEGenericBase< OutputShape > &fe, std::vector< std::vector< OutputShape > > &phi, bool add_p_level=true) const override
Evaluates shape functions in physical coordinates for conforming elements.
virtual void map_curl(const unsigned int dim, const Elem *const elem, const std::vector< Point > &qp, const FEGenericBase< OutputShape > &fe, std::vector< std::vector< OutputShape > > &curl_phi) const override
Evaluates the shape function curl in physical coordinates based on conforming finite element transfo...
virtual void init_map_dphi(const FEGenericBase< OutputShape > &fe) const override
Pre-requests any necessary data from FEMap.
virtual void init_map_d2phi(const FEGenericBase< OutputShape > &fe) const override
Pre-requests any necessary data from FEMap.
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
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real