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 : // C++ includes
21 : #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
22 : #include <cmath> // for std::sqrt
23 :
24 :
25 : // Local includes
26 : #include "libmesh/libmesh_common.h"
27 : #include "libmesh/fe.h"
28 : #include "libmesh/fe_interface.h"
29 : #include "libmesh/quadrature.h"
30 : #include "libmesh/elem.h"
31 : #include "libmesh/libmesh_logging.h"
32 : #include "libmesh/tensor_value.h" // May be necessary if destructors
33 : // get instantiated here
34 :
35 : namespace libMesh
36 : {
37 :
38 : //-------------------------------------------------------
39 : // Full specializations for useless methods in 0D, 1D
40 : #define REINIT_ERROR(_dim, _type, _func) \
41 : template <> \
42 : void FE<_dim,_type>::_func(const Elem *, \
43 : const unsigned int, \
44 : const Real, \
45 : const std::vector<Point> * const, \
46 : const std::vector<Real> * const)
47 :
48 : #define SIDEMAP_ERROR(_dim, _type, _func) \
49 : template <> \
50 : void FE<_dim,_type>::_func(const Elem *, \
51 : const Elem *, \
52 : const unsigned int, \
53 : const std::vector<Point> &, \
54 : std::vector<Point> &)
55 :
56 : #define FACE_EDGE_SHAPE_ERROR(_dim, _func) \
57 : template <> \
58 : void FEMap::_func<_dim>(const std::vector<Point> &, \
59 : const Elem *) \
60 : { \
61 : libmesh_error_msg("ERROR: This method makes no sense for low-D elements!"); \
62 : }
63 :
64 : // 0D error instantiations
65 : #define LIBMESH_ERRORS_IN_LOW_D(_type) \
66 : REINIT_ERROR(0, _type, reinit) { libmesh_error_msg("ERROR: Cannot reinit 0D " #_type " elements!"); } \
67 : REINIT_ERROR(0, _type, edge_reinit) { libmesh_error_msg("ERROR: Cannot edge_reinit 0D " #_type " elements!"); } \
68 : SIDEMAP_ERROR(0, _type, side_map) { libmesh_error_msg("ERROR: Cannot side_map 0D " #_type " elements!"); } \
69 : SIDEMAP_ERROR(0, _type, edge_map) { libmesh_error_msg("ERROR: Cannot edge_map 0D " #_type " elements!"); } \
70 : REINIT_ERROR(1, _type, edge_reinit) { libmesh_error_msg("ERROR: Cannot edge_reinit 1D " #_type " elements!"); } \
71 : SIDEMAP_ERROR(1, _type, edge_map) { libmesh_error_msg("ERROR: Cannot edge_map 1D " #_type " elements!"); }
72 :
73 0 : LIBMESH_ERRORS_IN_LOW_D(CLOUGH)
74 0 : LIBMESH_ERRORS_IN_LOW_D(HERMITE)
75 0 : LIBMESH_ERRORS_IN_LOW_D(HIERARCHIC)
76 0 : LIBMESH_ERRORS_IN_LOW_D(L2_HIERARCHIC)
77 0 : LIBMESH_ERRORS_IN_LOW_D(HIERARCHIC_VEC)
78 0 : LIBMESH_ERRORS_IN_LOW_D(L2_HIERARCHIC_VEC)
79 0 : LIBMESH_ERRORS_IN_LOW_D(SIDE_HIERARCHIC)
80 0 : LIBMESH_ERRORS_IN_LOW_D(LAGRANGE)
81 0 : LIBMESH_ERRORS_IN_LOW_D(L2_LAGRANGE)
82 0 : LIBMESH_ERRORS_IN_LOW_D(L2_LAGRANGE_GLL)
83 0 : LIBMESH_ERRORS_IN_LOW_D(LAGRANGE_VEC)
84 0 : LIBMESH_ERRORS_IN_LOW_D(L2_LAGRANGE_VEC)
85 0 : LIBMESH_ERRORS_IN_LOW_D(MONOMIAL)
86 0 : LIBMESH_ERRORS_IN_LOW_D(MONOMIAL_VEC)
87 0 : LIBMESH_ERRORS_IN_LOW_D(NEDELEC_ONE)
88 0 : LIBMESH_ERRORS_IN_LOW_D(RAVIART_THOMAS)
89 0 : LIBMESH_ERRORS_IN_LOW_D(L2_RAVIART_THOMAS)
90 0 : LIBMESH_ERRORS_IN_LOW_D(SCALAR)
91 0 : LIBMESH_ERRORS_IN_LOW_D(XYZ)
92 :
93 : #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
94 0 : LIBMESH_ERRORS_IN_LOW_D(BERNSTEIN)
95 0 : LIBMESH_ERRORS_IN_LOW_D(SZABAB)
96 0 : LIBMESH_ERRORS_IN_LOW_D(RATIONAL_BERNSTEIN)
97 : #endif
98 :
99 : // Special error instantiations
100 0 : REINIT_ERROR(1, NEDELEC_ONE, reinit) { libmesh_error_msg("ERROR: Cannot reinit 1D NEDELEC_ONE elements!"); }
101 0 : SIDEMAP_ERROR(1, NEDELEC_ONE, side_map) { libmesh_error_msg("ERROR: Cannot side_map 1D NEDELEC_ONE elements!"); }
102 0 : REINIT_ERROR(1, RAVIART_THOMAS, reinit) { libmesh_error_msg("ERROR: Cannot reinit 1D RAVIART_THOMAS elements!"); }
103 0 : SIDEMAP_ERROR(1, RAVIART_THOMAS, side_map) { libmesh_error_msg("ERROR: Cannot side_map 1D RAVIART_THOMAS elements!"); }
104 0 : REINIT_ERROR(1, L2_RAVIART_THOMAS, reinit) { libmesh_error_msg("ERROR: Cannot reinit 1D L2_RAVIART_THOMAS elements!"); }
105 0 : SIDEMAP_ERROR(1, L2_RAVIART_THOMAS, side_map) { libmesh_error_msg("ERROR: Cannot side_map 1D L2_RAVIART_THOMAS elements!"); }
106 :
107 : //-------------------------------------------------------
108 : // Methods for 2D, 3D
109 : template <unsigned int Dim, FEFamily T>
110 27918101 : void FE<Dim,T>::reinit(const Elem * elem,
111 : const unsigned int s,
112 : const Real /* tolerance */,
113 : const std::vector<Point> * const pts,
114 : const std::vector<Real> * const weights)
115 : {
116 2509141 : libmesh_assert(elem);
117 2509141 : libmesh_assert (this->qrule != nullptr || pts != nullptr);
118 : // We now do this for 1D elements!
119 : // libmesh_assert_not_equal_to (Dim, 1);
120 :
121 : // If we called this function redundantly (e.g. in an FEMContext
122 : // that is asked not to do any side calculations) then let's skip the
123 : // whole inverse_map process that calculates side points
124 27918101 : if (this->calculating_nothing())
125 : {
126 1891557 : this->calculations_started = true; // Ironic
127 1891557 : return;
128 : }
129 :
130 : // We're (possibly re-) calculating now! FIXME - we currently
131 : // expect to be able to use side_map and JxW later, but we could
132 : // optimize further here.
133 26026544 : this->_fe_map->add_calculations();
134 2343428 : this->_fe_map->get_JxW();
135 2343428 : this->_fe_map->get_xyz();
136 26026544 : this->determine_calculations();
137 :
138 : // Build the side of interest
139 26026544 : const std::unique_ptr<const Elem> side(elem->build_side_ptr(s));
140 :
141 : // Find the max p_level to select
142 : // the right quadrature rule for side integration
143 26026544 : unsigned int side_p_level = elem->p_level();
144 28369972 : if (elem->neighbor_ptr(s) != nullptr)
145 25314567 : side_p_level = std::max(side_p_level, elem->neighbor_ptr(s)->p_level());
146 :
147 : // Initialize the shape functions at the user-specified
148 : // points
149 26026544 : if (pts != nullptr)
150 : {
151 : // The shape functions do not correspond to the qrule
152 9399 : this->shapes_on_quadrature = false;
153 :
154 : // Initialize the face shape functions
155 9399 : this->_fe_map->template init_face_shape_functions<Dim>(*pts, side.get());
156 :
157 : // Compute the Jacobian*Weight on the face for integration
158 9399 : if (weights != nullptr)
159 : {
160 0 : this->_fe_map->compute_face_map (Dim, *weights, side.get());
161 : }
162 : else
163 : {
164 10035 : std::vector<Real> dummy_weights (pts->size(), 1.);
165 9399 : this->_fe_map->compute_face_map (Dim, dummy_weights, side.get());
166 : }
167 : }
168 : // If there are no user specified points, we use the
169 : // quadrature rule
170 : else
171 : {
172 : // initialize quadrature rule
173 26017145 : this->qrule->init(*side, side_p_level);
174 :
175 26017145 : if (this->qrule->shapes_need_reinit())
176 0 : this->shapes_on_quadrature = false;
177 :
178 : // FIXME - could this break if the same FE object was used
179 : // for both volume and face integrals? - RHS
180 : // We might not need to reinitialize the shape functions
181 49198957 : if ((this->get_type() != elem->type()) ||
182 25484907 : (elem->runtime_topology() &&
183 0 : this->_elem != elem) ||
184 25484907 : (side->type() != last_side) ||
185 46225774 : (this->_elem_p_level != side_p_level) ||
186 49136855 : this->shapes_need_reinit() ||
187 12243798 : !this->shapes_on_quadrature)
188 : {
189 : // Set the element
190 13773518 : this->_elem = elem;
191 13773518 : this->_elem_type = elem->type();
192 :
193 : // Set the last_side
194 13773518 : last_side = side->type();
195 :
196 : // Set the last p level
197 13773518 : this->_p_level = this->_add_p_level_in_reinit * side_p_level;
198 :
199 : // Initialize the face shape functions
200 14917937 : this->_fe_map->template init_face_shape_functions<Dim>(this->qrule->get_points(), side.get());
201 : }
202 : else
203 12243627 : this->_elem = elem;
204 :
205 : // Compute the Jacobian*Weight on the face for integration
206 28360255 : this->_fe_map->compute_face_map (Dim, this->qrule->get_weights(), side.get());
207 :
208 : // The shape functions correspond to the qrule
209 26017145 : this->shapes_on_quadrature = true;
210 : }
211 :
212 : // make a copy of the Jacobian for integration
213 28369972 : const std::vector<Real> JxW_int(this->_fe_map->get_JxW());
214 :
215 : // make a copy of shape on quadrature info
216 26026544 : bool shapes_on_quadrature_side = this->shapes_on_quadrature;
217 :
218 : // Find where the integration points are located on the
219 : // full element.
220 : const std::vector<Point> * ref_qp;
221 26026544 : if (pts != nullptr)
222 318 : ref_qp = pts;
223 : else
224 26017145 : ref_qp = &this->qrule->get_points();
225 :
226 4686856 : std::vector<Point> qp;
227 26026544 : this->side_map(elem, side.get(), s, *ref_qp, qp);
228 :
229 : // compute the shape function and derivative values
230 : // at the points qp
231 26026544 : this->reinit (elem, &qp);
232 :
233 26026544 : this->shapes_on_quadrature = shapes_on_quadrature_side;
234 :
235 26026544 : this->_elem_p_level = side_p_level;
236 :
237 : // copy back old data
238 26026544 : this->_fe_map->get_JxW() = JxW_int;
239 21339688 : }
240 :
241 :
242 :
243 : template <unsigned int Dim, FEFamily T>
244 179984 : void FE<Dim,T>::edge_reinit(const Elem * elem,
245 : const unsigned int e,
246 : const Real /* tolerance */,
247 : const std::vector<Point> * const pts,
248 : const std::vector<Real> * const weights)
249 : {
250 13087 : libmesh_assert(elem);
251 13087 : libmesh_assert (this->qrule != nullptr || pts != nullptr);
252 : // We don't do this for 1D elements!
253 : libmesh_assert_not_equal_to (Dim, 1);
254 :
255 : // We're (possibly re-) calculating now! Time to determine what.
256 : // FIXME - we currently just assume that we're using JxW and calling
257 : // edge_map later.
258 179984 : this->_fe_map->add_calculations();
259 13087 : this->_fe_map->get_JxW();
260 13087 : this->_fe_map->get_xyz();
261 179984 : this->determine_calculations();
262 :
263 : // Build the side of interest
264 179984 : const std::unique_ptr<const Elem> edge(elem->build_edge_ptr(e));
265 :
266 : // Initialize the shape functions at the user-specified
267 : // points
268 179984 : if (pts != nullptr)
269 : {
270 : // The shape functions do not correspond to the qrule
271 0 : this->shapes_on_quadrature = false;
272 :
273 : // Initialize the edge shape functions
274 0 : this->_fe_map->template init_edge_shape_functions<Dim> (*pts, edge.get());
275 :
276 : // Compute the Jacobian*Weight on the face for integration
277 0 : if (weights != nullptr)
278 : {
279 0 : this->_fe_map->compute_edge_map (Dim, *weights, edge.get());
280 : }
281 : else
282 : {
283 0 : std::vector<Real> dummy_weights (pts->size(), 1.);
284 0 : this->_fe_map->compute_edge_map (Dim, dummy_weights, edge.get());
285 : }
286 : }
287 : // If there are no user specified points, we use the
288 : // quadrature rule
289 : else
290 : {
291 : // initialize quadrature rule
292 193071 : this->qrule->init(*edge, elem->p_level());
293 :
294 179984 : if (this->qrule->shapes_need_reinit())
295 0 : this->shapes_on_quadrature = false;
296 :
297 : // We might not need to reinitialize the shape functions
298 338334 : if ((this->get_type() != elem->type()) ||
299 170979 : (elem->runtime_topology() &&
300 0 : this->_elem != elem) ||
301 316700 : (edge->type() != last_edge) ||
302 338334 : this->shapes_need_reinit() ||
303 36096 : !this->shapes_on_quadrature)
304 : {
305 : // Set the element
306 179984 : this->_elem = elem;
307 179984 : this->_elem_type = elem->type();
308 :
309 : // Set the last_edge
310 179984 : last_edge = edge->type();
311 :
312 : // Initialize the edge shape functions
313 193071 : this->_fe_map->template init_edge_shape_functions<Dim> (this->qrule->get_points(), edge.get());
314 : }
315 : else
316 0 : this->_elem = elem;
317 :
318 : // Compute the Jacobian*Weight on the face for integration
319 193071 : this->_fe_map->compute_edge_map (Dim, this->qrule->get_weights(), edge.get());
320 :
321 : // The shape functions correspond to the qrule
322 179984 : this->shapes_on_quadrature = true;
323 : }
324 :
325 : // make a copy of the Jacobian for integration
326 193071 : const std::vector<Real> JxW_int(this->_fe_map->get_JxW());
327 :
328 : // Find where the integration points are located on the
329 : // full element.
330 : const std::vector<Point> * ref_qp;
331 179984 : if (pts != nullptr)
332 0 : ref_qp = pts;
333 : else
334 179984 : ref_qp = & this->qrule->get_points();
335 :
336 26174 : std::vector<Point> qp;
337 179984 : this->edge_map(elem, edge.get(), e, *ref_qp, qp);
338 :
339 : // compute the shape function and derivative values
340 : // at the points qp
341 179984 : this->reinit (elem, &qp);
342 :
343 : // copy back old data
344 179984 : this->_fe_map->get_JxW() = JxW_int;
345 179984 : }
346 :
347 : template <unsigned int Dim, FEFamily T>
348 26054384 : void FE<Dim,T>::side_map (const Elem * elem,
349 : const Elem * side,
350 : const unsigned int s,
351 : const std::vector<Point> & reference_side_points,
352 : std::vector<Point> & reference_points)
353 : {
354 : // We're calculating mappings - we need at least first order info
355 26054384 : this->calculate_phi = true;
356 26054384 : this->determine_calculations();
357 :
358 26054384 : unsigned int side_p_level = elem->p_level();
359 28400132 : if (elem->neighbor_ptr(s) != nullptr)
360 25344929 : side_p_level = std::max(side_p_level, elem->neighbor_ptr(s)->p_level());
361 :
362 49753594 : if (side->type() != last_side ||
363 26044630 : (elem->runtime_topology() &&
364 0 : this->_elem != elem) ||
365 54444148 : side_p_level != this->_elem_p_level ||
366 26040096 : !this->shapes_on_quadrature)
367 : {
368 : // Set the element type
369 41590 : this->_elem = elem;
370 41590 : this->_elem_type = elem->type();
371 41590 : this->_elem_p_level = side_p_level;
372 41590 : this->_p_level = this->_add_p_level_in_reinit * side_p_level;
373 :
374 : // Set the last_side
375 41590 : last_side = side->type();
376 :
377 : // Initialize the face shape functions
378 41590 : this->_fe_map->template init_face_shape_functions<Dim>(reference_side_points, side);
379 : }
380 : else
381 26012794 : this->_elem = elem;
382 :
383 : const unsigned int n_points =
384 4691496 : cast_int<unsigned int>(reference_side_points.size());
385 26054384 : reference_points.resize(n_points);
386 110853894 : for (unsigned int i = 0; i < n_points; i++)
387 84799510 : reference_points[i].zero();
388 :
389 4691496 : std::vector<Point> refspace_nodes;
390 26054384 : this->get_refspace_nodes(elem->type(), refspace_nodes);
391 :
392 2345748 : const std::vector<std::vector<Real>> & psi_map = this->_fe_map->get_psi();
393 :
394 : // sum over the nodes
395 149621250 : for (auto i : index_range(psi_map))
396 : {
397 123566866 : const Point & side_node = refspace_nodes[elem->local_side_node(s,i)];
398 600066925 : for (unsigned int p=0; p<n_points; p++)
399 556841539 : reference_points[p].add_scaled (side_node, psi_map[i][p]);
400 : }
401 26054384 : }
402 :
403 : template <unsigned int Dim, FEFamily T>
404 179984 : void FE<Dim,T>::edge_map (const Elem * elem,
405 : const Elem * edge,
406 : const unsigned int e,
407 : const std::vector<Point> & reference_edge_points,
408 : std::vector<Point> & reference_points)
409 : {
410 : // We're calculating mappings - we need at least first order info
411 179984 : this->calculate_phi = true;
412 179984 : this->determine_calculations();
413 :
414 26174 : unsigned int edge_p_level = elem->p_level();
415 :
416 346881 : if (edge->type() != last_edge ||
417 179984 : (elem->runtime_topology() &&
418 0 : this->_elem != elem) ||
419 373055 : edge_p_level != this->_elem_p_level ||
420 179984 : !this->shapes_on_quadrature)
421 : {
422 : // Set the element type
423 0 : this->_elem = elem;
424 0 : this->_elem_type = elem->type();
425 0 : this->_elem_p_level = edge_p_level;
426 0 : this->_p_level = this->_add_p_level_in_reinit * edge_p_level;
427 :
428 : // Set the last_edge
429 0 : last_edge = edge->type();
430 :
431 : // Initialize the edge shape functions
432 0 : this->_fe_map->template init_edge_shape_functions<Dim>(reference_edge_points, edge);
433 : }
434 : else
435 179984 : this->_elem = elem;
436 :
437 : const unsigned int n_points =
438 26174 : cast_int<unsigned int>(reference_edge_points.size());
439 179984 : reference_points.resize(n_points);
440 865037 : for (unsigned int i = 0; i < n_points; i++)
441 685053 : reference_points[i].zero();
442 :
443 26174 : std::vector<Point> refspace_nodes;
444 179984 : this->get_refspace_nodes(elem->type(), refspace_nodes);
445 :
446 13087 : const std::vector<std::vector<Real>> & psi_map = this->_fe_map->get_psi();
447 :
448 : // sum over the nodes
449 719900 : for (auto i : index_range(psi_map))
450 : {
451 539916 : const Point & edge_node = refspace_nodes[elem->local_edge_node(e,i)];
452 2595003 : for (unsigned int p=0; p<n_points; p++)
453 2354883 : reference_points[p].add_scaled (edge_node, psi_map[i][p]);
454 : }
455 179984 : }
456 :
457 :
458 : template<unsigned int Dim>
459 15545523 : void FEMap::init_face_shape_functions(const std::vector<Point> & qp,
460 : const Elem * side)
461 : {
462 : // Start logging the shape function initialization
463 3873215 : LOG_SCOPE("init_face_shape_functions()", "FEMap");
464 :
465 1291073 : libmesh_assert(side);
466 :
467 : // We're calculating now!
468 1291073 : this->determine_calculations();
469 :
470 : // The element type and order to use in
471 : // the map
472 15545523 : const FEFamily mapping_family = FEMap::map_fe_type(*side);
473 15545523 : const FEType map_fe_type(side->default_order(), mapping_family);
474 :
475 : // The number of quadrature points.
476 2582142 : const unsigned int n_qp = cast_int<unsigned int>(qp.size());
477 :
478 : // Do not use the p_level(), if any, that is inherited by the side.
479 : const unsigned int n_mapping_shape_functions =
480 15545523 : FEInterface::n_shape_functions(map_fe_type, /*extra_order=*/0, side);
481 :
482 : // resize the vectors to hold current data
483 : // Psi are the shape functions used for the FE mapping
484 15545523 : if (calculate_xyz)
485 15517683 : this->psi_map.resize (n_mapping_shape_functions);
486 :
487 : if (Dim > 1)
488 : {
489 15474101 : if (calculate_dxyz)
490 15294245 : this->dpsidxi_map.resize (n_mapping_shape_functions);
491 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
492 15474101 : if (calculate_d2xyz)
493 421949 : this->d2psidxi2_map.resize (n_mapping_shape_functions);
494 : #endif
495 : }
496 :
497 : if (Dim == 3)
498 : {
499 9436879 : if (calculate_dxyz)
500 9289423 : this->dpsideta_map.resize (n_mapping_shape_functions);
501 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
502 9436879 : if (calculate_d2xyz)
503 : {
504 292800 : this->d2psidxideta_map.resize (n_mapping_shape_functions);
505 292800 : this->d2psideta2_map.resize (n_mapping_shape_functions);
506 : }
507 : #endif
508 : }
509 :
510 : FEInterface::shape_ptr shape_ptr =
511 15545523 : FEInterface::shape_function(map_fe_type, side);
512 :
513 : FEInterface::shape_deriv_ptr shape_deriv_ptr =
514 15545523 : FEInterface::shape_deriv_function(map_fe_type, side);
515 :
516 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
517 : FEInterface::shape_second_deriv_ptr shape_second_deriv_ptr =
518 15545523 : FEInterface::shape_second_deriv_function(map_fe_type, side);
519 : #endif
520 :
521 99850256 : for (unsigned int i=0; i<n_mapping_shape_functions; i++)
522 : {
523 : // Allocate space to store the values of the shape functions
524 : // and their first and second derivatives at the quadrature points.
525 84304733 : if (calculate_xyz)
526 91177576 : this->psi_map[i].resize (n_qp);
527 : if (Dim > 1)
528 : {
529 84233311 : if (calculate_dxyz)
530 89997423 : this->dpsidxi_map[i].resize (n_qp);
531 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
532 84233311 : if (calculate_d2xyz)
533 2733613 : this->d2psidxi2_map[i].resize (n_qp);
534 : #endif
535 : }
536 : if (Dim == 3)
537 : {
538 66169054 : if (calculate_dxyz)
539 70535114 : this->dpsideta_map[i].resize (n_qp);
540 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
541 66169054 : if (calculate_d2xyz)
542 : {
543 2314000 : this->d2psidxideta_map[i].resize (n_qp);
544 2314000 : this->d2psideta2_map[i].resize (n_qp);
545 : }
546 : #endif
547 : }
548 :
549 :
550 : // Compute the value of mapping shape function i, and its first
551 : // and second derivatives at quadrature point p
552 435485559 : for (unsigned int p=0; p<n_qp; p++)
553 : {
554 351180826 : if (calculate_xyz)
555 379260639 : this->psi_map[i][p] = shape_ptr (map_fe_type, side, i, qp[p], false);
556 : if (Dim > 1)
557 : {
558 351109404 : if (calculate_dxyz)
559 375513094 : this->dpsidxi_map[i][p] = shape_deriv_ptr (map_fe_type, side, i, 0, qp[p], false);
560 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
561 351109404 : if (calculate_d2xyz)
562 21828506 : this->d2psidxi2_map[i][p] = shape_second_deriv_ptr(map_fe_type, side, i, 0, qp[p], false);
563 : #endif
564 : }
565 : // libMesh::out << "this->d2psidxi2_map["<<i<<"][p]=" << d2psidxi2_map[i][p] << std::endl;
566 :
567 : // If we are in 3D, then our sides are 2D faces.
568 : // For the second derivatives, we must also compute the cross
569 : // derivative d^2() / dxi deta
570 : if (Dim == 3)
571 : {
572 302398316 : if (calculate_dxyz)
573 322962768 : this->dpsideta_map[i][p] = shape_deriv_ptr (map_fe_type, side, i, 1, qp[p], false);
574 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
575 302398316 : if (calculate_d2xyz)
576 : {
577 20911280 : this->d2psidxideta_map[i][p] = shape_second_deriv_ptr(map_fe_type, side, i, 1, qp[p], false);
578 20911280 : this->d2psideta2_map[i][p] = shape_second_deriv_ptr(map_fe_type, side, i, 2, qp[p], false);
579 : }
580 : #endif
581 : }
582 : }
583 : }
584 15545523 : }
585 :
586 : template<unsigned int Dim>
587 179984 : void FEMap::init_edge_shape_functions(const std::vector<Point> & qp,
588 : const Elem * edge)
589 : {
590 : // Start logging the shape function initialization
591 39261 : LOG_SCOPE("init_edge_shape_functions()", "FEMap");
592 :
593 13087 : libmesh_assert(edge);
594 :
595 : // We're calculating now!
596 13087 : this->determine_calculations();
597 :
598 : // The element type and order to use in
599 : // the map
600 179984 : const FEFamily mapping_family = FEMap::map_fe_type(*edge);
601 179984 : const FEType map_fe_type(edge->default_order(), mapping_family);
602 :
603 : // The number of quadrature points.
604 26174 : const unsigned int n_qp = cast_int<unsigned int>(qp.size());
605 :
606 : // Do not use the p_level(), if any, that is inherited by the side.
607 : const unsigned int n_mapping_shape_functions =
608 179984 : FEInterface::n_shape_functions(map_fe_type, /*extra_order=*/0, edge);
609 :
610 : // resize the vectors to hold current data
611 : // Psi are the shape functions used for the FE mapping
612 179984 : if (calculate_xyz)
613 179984 : this->psi_map.resize (n_mapping_shape_functions);
614 179984 : if (calculate_dxyz)
615 179984 : this->dpsidxi_map.resize (n_mapping_shape_functions);
616 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
617 179984 : if (calculate_d2xyz)
618 0 : this->d2psidxi2_map.resize (n_mapping_shape_functions);
619 : #endif
620 :
621 : FEInterface::shape_ptr shape_ptr =
622 179984 : FEInterface::shape_function(map_fe_type, edge);
623 :
624 : FEInterface::shape_deriv_ptr shape_deriv_ptr =
625 179984 : FEInterface::shape_deriv_function(map_fe_type, edge);
626 :
627 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
628 : FEInterface::shape_second_deriv_ptr shape_second_deriv_ptr =
629 179984 : FEInterface::shape_second_deriv_function(map_fe_type, edge);
630 : #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
631 :
632 719900 : for (unsigned int i=0; i<n_mapping_shape_functions; i++)
633 : {
634 : // Allocate space to store the values of the shape functions
635 : // and their first and second derivatives at the quadrature points.
636 539916 : if (calculate_xyz)
637 579174 : this->psi_map[i].resize (n_qp);
638 539916 : if (calculate_dxyz)
639 579174 : this->dpsidxi_map[i].resize (n_qp);
640 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
641 539916 : if (calculate_d2xyz)
642 0 : this->d2psidxi2_map[i].resize (n_qp);
643 : #endif
644 :
645 : // Compute the value of mapping shape function i, and its first
646 : // and second derivatives at quadrature point p
647 2595003 : for (unsigned int p=0; p<n_qp; p++)
648 : {
649 2055087 : if (calculate_xyz)
650 2204985 : this->psi_map[i][p] = shape_ptr (map_fe_type, edge, i, qp[p], false);
651 2055087 : if (calculate_dxyz)
652 2204985 : this->dpsidxi_map[i][p] = shape_deriv_ptr (map_fe_type, edge, i, 0, qp[p], false);
653 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
654 2055087 : if (calculate_d2xyz)
655 0 : this->d2psidxi2_map[i][p] = shape_second_deriv_ptr(map_fe_type, edge, i, 0, qp[p], false);
656 : #endif
657 : }
658 : }
659 179984 : }
660 :
661 :
662 :
663 27747560 : void FEMap::compute_face_map(int dim, const std::vector<Real> & qw,
664 : const Elem * side)
665 : {
666 2486846 : libmesh_assert(side);
667 :
668 : // We're calculating now!
669 2486846 : this->determine_calculations();
670 :
671 7460538 : LOG_ONE_ENTITY_SCOPE("compute_face_map()", "FEMap");
672 :
673 : // The number of quadrature points.
674 4973692 : const unsigned int n_qp = cast_int<unsigned int>(qw.size());
675 :
676 27747560 : const FEFamily mapping_family = FEMap::map_fe_type(*side);
677 27747560 : const Order mapping_order (side->default_order());
678 2486846 : const FEType map_fe_type(mapping_order, mapping_family);
679 :
680 : // Do not use the p_level(), if any, that is inherited by the side.
681 : const unsigned int n_mapping_shape_functions =
682 27747560 : FEInterface::n_shape_functions(map_fe_type, /*extra_order=*/0, side);
683 :
684 27747560 : switch (dim)
685 : {
686 73008 : case 1:
687 : {
688 : // A 1D finite element, potentially in 2D or 3D space.
689 : // This means the boundary is a "0D finite element", a
690 : // NODEELEM.
691 :
692 : // Resize the vectors to hold data at the quadrature points
693 : {
694 73008 : if (calculate_xyz)
695 73008 : this->xyz.resize(n_qp);
696 73008 : if (calculate_dxyz)
697 73008 : normals.resize(n_qp);
698 :
699 73008 : if (calculate_dxyz)
700 73008 : this->JxW.resize(n_qp);
701 : }
702 :
703 : // If we have no quadrature points, there's nothing else to do
704 73008 : if (!n_qp)
705 0 : break;
706 :
707 : // We need to look back at the full edge to figure out the normal
708 : // vector
709 73008 : const Elem * elem = side->interior_parent();
710 6059 : libmesh_assert (elem);
711 73008 : if (calculate_dxyz)
712 : {
713 85126 : if (side->node_id(0) == elem->node_id(0))
714 : {
715 2185 : const Point reference_point = Point(-1.);
716 28112 : Point dx_dxi = FEMap::map_deriv (1, elem, 0, reference_point);
717 28112 : normals[0] = -dx_dxi.unit();
718 : }
719 : else
720 : {
721 3874 : libmesh_assert_equal_to (side->node_id(0),
722 : elem->node_id(1));
723 3874 : const Point reference_point = Point(1.);
724 44896 : Point dx_dxi = FEMap::map_deriv (1, elem, 0, reference_point);
725 44896 : normals[0] = dx_dxi.unit();
726 : }
727 : }
728 :
729 : // Calculate x at the point
730 73008 : if (calculate_xyz)
731 6059 : libmesh_assert_equal_to (this->psi_map.size(), 1);
732 : // In the unlikely event we have multiple quadrature
733 : // points, they'll be in the same place
734 146016 : for (unsigned int p=0; p<n_qp; p++)
735 : {
736 73008 : if (calculate_xyz)
737 : {
738 73008 : this->xyz[p].zero();
739 79067 : this->xyz[p].add_scaled (side->point(0), this->psi_map[0][p]);
740 : }
741 73008 : if (calculate_dxyz)
742 : {
743 73008 : normals[p] = normals[0];
744 85126 : this->JxW[p] = 1.0*qw[p];
745 : }
746 : }
747 :
748 : // done computing the map
749 6059 : break;
750 : }
751 :
752 12945387 : case 2:
753 : {
754 : // A 2D finite element living in either 2D or 3D space.
755 : // This means the boundary is a 1D finite element, i.e.
756 : // and EDGE2 or EDGE3.
757 : // Resize the vectors to hold data at the quadrature points
758 : {
759 12945387 : if (calculate_xyz)
760 12945387 : this->xyz.resize(n_qp);
761 12945387 : if (calculate_dxyz)
762 : {
763 12912987 : this->dxyzdxi_map.resize(n_qp);
764 12912987 : this->tangents.resize(n_qp);
765 12912987 : this->normals.resize(n_qp);
766 :
767 12912987 : this->JxW.resize(n_qp);
768 : }
769 :
770 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
771 12945387 : if (calculate_d2xyz)
772 : {
773 129149 : this->d2xyzdxi2_map.resize(n_qp);
774 129149 : this->curvatures.resize(n_qp);
775 : }
776 : #endif
777 : }
778 :
779 : // Clear the entities that will be summed
780 : // Compute the tangent & normal at the quadrature point
781 39091723 : for (unsigned int p=0; p<n_qp; p++)
782 : {
783 26146336 : if (calculate_xyz)
784 26146336 : this->xyz[p].zero();
785 26146336 : if (calculate_dxyz)
786 : {
787 28439719 : this->tangents[p].resize(LIBMESH_DIM-1); // 1 Tangent in 2D, 2 in 3D
788 4716366 : this->dxyzdxi_map[p].zero();
789 : }
790 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
791 26146336 : if (calculate_d2xyz)
792 282298 : this->d2xyzdxi2_map[p].zero();
793 : #endif
794 : }
795 :
796 : // compute x, dxdxi at the quadrature points
797 46770077 : for (unsigned int i=0; i<n_mapping_shape_functions; i++) // sum over the nodes
798 : {
799 6346784 : const Point & side_point = side->point(i);
800 :
801 106943360 : for (unsigned int p=0; p<n_qp; p++) // for each quadrature point...
802 : {
803 73118670 : if (calculate_xyz)
804 86077944 : this->xyz[p].add_scaled (side_point, this->psi_map[i][p]);
805 73118670 : if (calculate_dxyz)
806 85851144 : this->dxyzdxi_map[p].add_scaled (side_point, this->dpsidxi_map[i][p]);
807 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
808 73118670 : if (calculate_d2xyz)
809 987558 : this->d2xyzdxi2_map[p].add_scaled(side_point, this->d2psidxi2_map[i][p]);
810 : #endif
811 : }
812 : }
813 :
814 : // Compute the tangent & normal at the quadrature point
815 12945387 : if (calculate_dxyz)
816 : {
817 38994523 : for (unsigned int p=0; p<n_qp; p++)
818 : {
819 : // The first tangent comes from just the edge's Jacobian
820 28439719 : this->tangents[p][0] = this->dxyzdxi_map[p].unit();
821 :
822 : #if LIBMESH_DIM == 2
823 : // For a 2D element living in 2D, the normal is given directly
824 : // from the entries in the edge Jacobian.
825 : this->normals[p] = (Point(this->dxyzdxi_map[p](1), -this->dxyzdxi_map[p](0), 0.)).unit();
826 :
827 : #elif LIBMESH_DIM == 3
828 : // For a 2D element living in 3D, there is a second tangent.
829 : // For the second tangent, we need to refer to the full
830 : // element's (not just the edge's) Jacobian.
831 26081536 : const Elem * elem = side->interior_parent();
832 2358183 : libmesh_assert(elem);
833 :
834 : // Inverse map xyz[p] to a reference point on the parent...
835 28439719 : Point reference_point = FEMap::inverse_map(2, elem, this->xyz[p]);
836 :
837 : // Get dxyz/dxi and dxyz/deta from the parent map.
838 26081536 : Point dx_dxi = FEMap::map_deriv (2, elem, 0, reference_point);
839 26081536 : Point dx_deta = FEMap::map_deriv (2, elem, 1, reference_point);
840 :
841 : // The second tangent vector is formed by crossing these vectors.
842 26081536 : tangents[p][1] = dx_dxi.cross(dx_deta).unit();
843 :
844 : // Finally, the normal in this case is given by crossing these
845 : // two tangents.
846 26081536 : normals[p] = tangents[p][0].cross(tangents[p][1]).unit();
847 : #endif
848 :
849 :
850 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
851 : // The curvature is computed via the familiar Frenet formula:
852 : // curvature = [d^2(x) / d (xi)^2] dot [normal]
853 : // For a reference, see:
854 : // F.S. Merritt, Mathematics Manual, 1962, McGraw-Hill, p. 310
855 : //
856 : // Note: The sign convention here is different from the
857 : // 3D case. Concave-upward curves (smiles) have a positive
858 : // curvature. Concave-downward curves (frowns) have a
859 : // negative curvature. Be sure to take that into account!
860 26081536 : if (calculate_d2xyz)
861 : {
862 46888 : const Real numerator = this->d2xyzdxi2_map[p] * this->normals[p];
863 46888 : const Real denominator = this->dxyzdxi_map[p].norm_sq();
864 23444 : libmesh_assert_not_equal_to (denominator, 0);
865 305742 : curvatures[p] = numerator / denominator;
866 : }
867 : #endif
868 : }
869 :
870 : // compute the jacobian at the quadrature points
871 38994523 : for (unsigned int p=0; p<n_qp; p++)
872 : {
873 26081536 : const Real the_jac = this->dxyzdxi_map[p].norm();
874 :
875 2358183 : libmesh_assert_greater (the_jac, 0.);
876 :
877 30797902 : this->JxW[p] = the_jac*qw[p];
878 : }
879 : }
880 :
881 : // done computing the map
882 1253178 : break;
883 : }
884 :
885 :
886 :
887 14729165 : case 3:
888 : {
889 : // A 3D finite element living in 3D space.
890 : // Resize the vectors to hold data at the quadrature points
891 : {
892 14729165 : if (calculate_xyz)
893 14729165 : this->xyz.resize(n_qp);
894 14729165 : if (calculate_dxyz)
895 : {
896 14581709 : this->dxyzdxi_map.resize(n_qp);
897 14581709 : this->dxyzdeta_map.resize(n_qp);
898 14581709 : this->tangents.resize(n_qp);
899 14581709 : this->normals.resize(n_qp);
900 14581709 : this->JxW.resize(n_qp);
901 : }
902 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
903 14729165 : if (calculate_d2xyz)
904 : {
905 292800 : this->d2xyzdxi2_map.resize(n_qp);
906 292800 : this->d2xyzdxideta_map.resize(n_qp);
907 292800 : this->d2xyzdeta2_map.resize(n_qp);
908 292800 : this->curvatures.resize(n_qp);
909 : }
910 : #endif
911 : }
912 :
913 : // Clear the entities that will be summed
914 79485110 : for (unsigned int p=0; p<n_qp; p++)
915 : {
916 64755945 : if (calculate_xyz)
917 64755945 : this->xyz[p].zero();
918 64755945 : if (calculate_dxyz)
919 : {
920 69522523 : this->tangents[p].resize(LIBMESH_DIM-1); // 1 Tangent in 2D, 2 in 3D
921 10712804 : this->dxyzdxi_map[p].zero();
922 10712804 : this->dxyzdeta_map[p].zero();
923 : }
924 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
925 64755945 : if (calculate_d2xyz)
926 : {
927 2621760 : this->d2xyzdxi2_map[p].zero();
928 436960 : this->d2xyzdxideta_map[p].zero();
929 436960 : this->d2xyzdeta2_map[p].zero();
930 : }
931 : #endif
932 : }
933 :
934 : // compute x, dxdxi at the quadrature points
935 115496485 : for (unsigned int i=0; i<n_mapping_shape_functions; i++) // sum over the nodes
936 : {
937 16798252 : const Point & side_point = side->point(i);
938 :
939 547044869 : for (unsigned int p=0; p<n_qp; p++) // for each quadrature point...
940 : {
941 446277549 : if (calculate_xyz)
942 520809165 : this->xyz[p].add_scaled (side_point, this->psi_map[i][p]);
943 446277549 : if (calculate_dxyz)
944 : {
945 515992269 : this->dxyzdxi_map[p].add_scaled (side_point, this->dpsidxi_map[i][p]);
946 515992269 : this->dxyzdeta_map[p].add_scaled(side_point, this->dpsideta_map[i][p]);
947 : }
948 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
949 446277549 : if (calculate_d2xyz)
950 : {
951 22519840 : this->d2xyzdxi2_map[p].add_scaled (side_point, this->d2psidxi2_map[i][p]);
952 22519840 : this->d2xyzdxideta_map[p].add_scaled(side_point, this->d2psidxideta_map[i][p]);
953 22519840 : this->d2xyzdeta2_map[p].add_scaled (side_point, this->d2psideta2_map[i][p]);
954 : }
955 : #endif
956 : }
957 : }
958 :
959 : // Compute the tangents, normal, and curvature at the quadrature point
960 14729165 : if (calculate_dxyz)
961 : {
962 78747830 : for (unsigned int p=0; p<n_qp; p++)
963 : {
964 69522523 : const Point n = this->dxyzdxi_map[p].cross(this->dxyzdeta_map[p]);
965 64166121 : this->normals[p] = n.unit();
966 69522523 : this->tangents[p][0] = this->dxyzdxi_map[p].unit();
967 69522523 : this->tangents[p][1] = n.cross(this->dxyzdxi_map[p]).unit();
968 :
969 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
970 64166121 : if (calculate_d2xyz)
971 : {
972 : // Compute curvature using the typical nomenclature
973 : // of the first and second fundamental forms.
974 : // For reference, see:
975 : // 1) http://mathworld.wolfram.com/MeanCurvature.html
976 : // (note -- they are using inward normal)
977 : // 2) F.S. Merritt, Mathematics Manual, 1962, McGraw-Hill
978 655440 : const Real L = -this->d2xyzdxi2_map[p] * this->normals[p];
979 436960 : const Real M = -this->d2xyzdxideta_map[p] * this->normals[p];
980 436960 : const Real N = -this->d2xyzdeta2_map[p] * this->normals[p];
981 436960 : const Real E = this->dxyzdxi_map[p].norm_sq();
982 436960 : const Real F = this->dxyzdxi_map[p] * this->dxyzdeta_map[p];
983 218480 : const Real G = this->dxyzdeta_map[p].norm_sq();
984 :
985 2621760 : const Real numerator = E*N -2.*F*M + G*L;
986 2621760 : const Real denominator = E*G - F*F;
987 218480 : libmesh_assert_not_equal_to (denominator, 0.);
988 2840240 : curvatures[p] = 0.5*numerator/denominator;
989 : }
990 : #endif
991 : }
992 :
993 : // compute the jacobian at the quadrature points, see
994 : // http://sp81.msi.umn.edu:999/fluent/fidap/help/theory/thtoc.htm
995 78747830 : for (unsigned int p=0; p<n_qp; p++)
996 : {
997 64166121 : const Real g11 = (dxdxi_map(p)*dxdxi_map(p) +
998 64166121 : dydxi_map(p)*dydxi_map(p) +
999 64166121 : dzdxi_map(p)*dzdxi_map(p));
1000 :
1001 64166121 : const Real g12 = (dxdxi_map(p)*dxdeta_map(p) +
1002 64166121 : dydxi_map(p)*dydeta_map(p) +
1003 64166121 : dzdxi_map(p)*dzdeta_map(p));
1004 :
1005 5356402 : const Real g21 = g12;
1006 :
1007 69522523 : const Real g22 = (dxdeta_map(p)*dxdeta_map(p) +
1008 64166121 : dydeta_map(p)*dydeta_map(p) +
1009 64166121 : dzdeta_map(p)*dzdeta_map(p));
1010 :
1011 :
1012 64166121 : const Real the_jac = std::sqrt(g11*g22 - g12*g21);
1013 :
1014 5356402 : libmesh_assert_greater (the_jac, 0.);
1015 :
1016 74878925 : this->JxW[p] = the_jac*qw[p];
1017 : }
1018 : }
1019 :
1020 : // done computing the map
1021 1227609 : break;
1022 : }
1023 :
1024 :
1025 0 : default:
1026 0 : libmesh_error_msg("Invalid dimension dim = " << dim);
1027 : }
1028 27747560 : }
1029 :
1030 :
1031 :
1032 :
1033 179984 : void FEMap::compute_edge_map(int dim,
1034 : const std::vector<Real> & qw,
1035 : const Elem * edge)
1036 : {
1037 13087 : libmesh_assert(edge);
1038 :
1039 179984 : if (dim == 2)
1040 : {
1041 : // A 2D finite element living in either 2D or 3D space.
1042 : // The edges here are the sides of the element, so the
1043 : // (misnamed) compute_face_map function does what we want
1044 0 : this->compute_face_map(dim, qw, edge);
1045 0 : return;
1046 : }
1047 :
1048 13087 : libmesh_assert_equal_to (dim, 3); // 1D is unnecessary and currently unsupported
1049 :
1050 39261 : LOG_ONE_ENTITY_SCOPE("compute_edge_map()", "FEMap");
1051 :
1052 : // We're calculating now!
1053 13087 : this->determine_calculations();
1054 :
1055 : // The number of quadrature points.
1056 26174 : const unsigned int n_qp = cast_int<unsigned int>(qw.size());
1057 :
1058 : // Resize the vectors to hold data at the quadrature points
1059 179984 : if (calculate_xyz)
1060 179984 : this->xyz.resize(n_qp);
1061 179984 : if (calculate_dxyz)
1062 : {
1063 179984 : this->dxyzdxi_map.resize(n_qp);
1064 179984 : this->dxyzdeta_map.resize(n_qp);
1065 179984 : this->tangents.resize(n_qp);
1066 179984 : this->normals.resize(n_qp);
1067 179984 : this->JxW.resize(n_qp);
1068 : }
1069 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1070 179984 : if (calculate_d2xyz)
1071 : {
1072 0 : this->d2xyzdxi2_map.resize(n_qp);
1073 0 : this->d2xyzdxideta_map.resize(n_qp);
1074 0 : this->d2xyzdeta2_map.resize(n_qp);
1075 0 : this->curvatures.resize(n_qp);
1076 : }
1077 : #endif
1078 :
1079 : // Clear the entities that will be summed
1080 865037 : for (unsigned int p=0; p<n_qp; p++)
1081 : {
1082 685053 : if (calculate_xyz)
1083 685053 : this->xyz[p].zero();
1084 685053 : if (calculate_dxyz)
1085 : {
1086 735021 : this->tangents[p].resize(1);
1087 99936 : this->dxyzdxi_map[p].zero();
1088 99936 : this->dxyzdeta_map[p].zero();
1089 : }
1090 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1091 685053 : if (calculate_d2xyz)
1092 : {
1093 0 : this->d2xyzdxi2_map[p].zero();
1094 0 : this->d2xyzdxideta_map[p].zero();
1095 0 : this->d2xyzdeta2_map[p].zero();
1096 : }
1097 : #endif
1098 : }
1099 :
1100 : // compute x, dxdxi at the quadrature points
1101 693726 : for (unsigned int i=0,
1102 26174 : psi_map_size=cast_int<unsigned int>(psi_map.size());
1103 719900 : i != psi_map_size; i++) // sum over the nodes
1104 : {
1105 78516 : const Point & edge_point = edge->point(i);
1106 :
1107 2595003 : for (unsigned int p=0; p<n_qp; p++) // for each quadrature point...
1108 : {
1109 2055087 : if (calculate_xyz)
1110 2204985 : this->xyz[p].add_scaled (edge_point, this->psi_map[i][p]);
1111 2055087 : if (calculate_dxyz)
1112 2354883 : this->dxyzdxi_map[p].add_scaled (edge_point, this->dpsidxi_map[i][p]);
1113 : #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1114 2055087 : if (calculate_d2xyz)
1115 0 : this->d2xyzdxi2_map[p].add_scaled (edge_point, this->d2psidxi2_map[i][p]);
1116 : #endif
1117 : }
1118 : }
1119 :
1120 : // Compute the tangents at the quadrature point
1121 : // FIXME: normals (plural!) and curvatures are uncalculated
1122 179984 : if (calculate_dxyz)
1123 865037 : for (unsigned int p=0; p<n_qp; p++)
1124 : {
1125 : // const Point n = this->dxyzdxi_map[p].cross(this->dxyzdeta_map[p]);
1126 735021 : this->tangents[p][0] = this->dxyzdxi_map[p].unit();
1127 :
1128 : // compute the jacobian at the quadrature points
1129 685053 : const Real the_jac = std::sqrt(this->dxdxi_map(p)*this->dxdxi_map(p) +
1130 685053 : this->dydxi_map(p)*this->dydxi_map(p) +
1131 685053 : this->dzdxi_map(p)*this->dzdxi_map(p));
1132 :
1133 49968 : libmesh_assert_greater (the_jac, 0.);
1134 :
1135 784989 : this->JxW[p] = the_jac*qw[p];
1136 : }
1137 : }
1138 :
1139 :
1140 : // Explicit FEMap Instantiations
1141 0 : FACE_EDGE_SHAPE_ERROR(0,init_face_shape_functions)
1142 : template LIBMESH_EXPORT void FEMap::init_face_shape_functions<1>(const std::vector<Point> &, const Elem *);
1143 : template LIBMESH_EXPORT void FEMap::init_face_shape_functions<2>(const std::vector<Point> &, const Elem *);
1144 : template LIBMESH_EXPORT void FEMap::init_face_shape_functions<3>(const std::vector<Point> &, const Elem *);
1145 :
1146 0 : FACE_EDGE_SHAPE_ERROR(0,init_edge_shape_functions)
1147 : template LIBMESH_EXPORT void FEMap::init_edge_shape_functions<1>(const std::vector<Point> &, const Elem *);
1148 : template LIBMESH_EXPORT void FEMap::init_edge_shape_functions<2>(const std::vector<Point> &, const Elem *);
1149 : template LIBMESH_EXPORT void FEMap::init_edge_shape_functions<3>(const std::vector<Point> &, const Elem *);
1150 :
1151 : //--------------------------------------------------------------
1152 : // Explicit FE instantiations
1153 : #define REINIT_AND_SIDE_MAPS(_type) \
1154 : template LIBMESH_EXPORT void FE<1,_type>::reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const); \
1155 : template LIBMESH_EXPORT void FE<1,_type>::side_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &); \
1156 : template LIBMESH_EXPORT void FE<2,_type>::reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const); \
1157 : template LIBMESH_EXPORT void FE<2,_type>::side_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &); \
1158 : template LIBMESH_EXPORT void FE<2,_type>::edge_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &); \
1159 : template LIBMESH_EXPORT void FE<2,_type>::edge_reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const); \
1160 : template LIBMESH_EXPORT void FE<3,_type>::reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const); \
1161 : template LIBMESH_EXPORT void FE<3,_type>::side_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &); \
1162 : template LIBMESH_EXPORT void FE<3,_type>::edge_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &); \
1163 : template LIBMESH_EXPORT void FE<3,_type>::edge_reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const)
1164 :
1165 : REINIT_AND_SIDE_MAPS(LAGRANGE);
1166 : REINIT_AND_SIDE_MAPS(LAGRANGE_VEC);
1167 : REINIT_AND_SIDE_MAPS(L2_LAGRANGE);
1168 : REINIT_AND_SIDE_MAPS(L2_LAGRANGE_GLL);
1169 : REINIT_AND_SIDE_MAPS(L2_LAGRANGE_VEC);
1170 : REINIT_AND_SIDE_MAPS(HIERARCHIC);
1171 : REINIT_AND_SIDE_MAPS(HIERARCHIC_VEC);
1172 : REINIT_AND_SIDE_MAPS(L2_HIERARCHIC);
1173 : REINIT_AND_SIDE_MAPS(L2_HIERARCHIC_VEC);
1174 : REINIT_AND_SIDE_MAPS(SIDE_HIERARCHIC);
1175 : REINIT_AND_SIDE_MAPS(CLOUGH);
1176 : REINIT_AND_SIDE_MAPS(HERMITE);
1177 : REINIT_AND_SIDE_MAPS(MONOMIAL);
1178 : REINIT_AND_SIDE_MAPS(MONOMIAL_VEC);
1179 : REINIT_AND_SIDE_MAPS(SCALAR);
1180 : REINIT_AND_SIDE_MAPS(XYZ);
1181 :
1182 : #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
1183 : REINIT_AND_SIDE_MAPS(BERNSTEIN);
1184 : REINIT_AND_SIDE_MAPS(SZABAB);
1185 : REINIT_AND_SIDE_MAPS(RATIONAL_BERNSTEIN);
1186 : #endif
1187 :
1188 : template LIBMESH_EXPORT void FE<2,SUBDIVISION>::reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1189 : template LIBMESH_EXPORT void FE<2,SUBDIVISION>::edge_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1190 :
1191 : template LIBMESH_EXPORT void FE<2,NEDELEC_ONE>::reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1192 : template LIBMESH_EXPORT void FE<2,NEDELEC_ONE>::side_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1193 : template LIBMESH_EXPORT void FE<2,NEDELEC_ONE>::edge_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1194 : template LIBMESH_EXPORT void FE<2,NEDELEC_ONE>::edge_reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1195 :
1196 : template LIBMESH_EXPORT void FE<2,RAVIART_THOMAS>::reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1197 : template LIBMESH_EXPORT void FE<2,RAVIART_THOMAS>::side_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1198 : template LIBMESH_EXPORT void FE<2,RAVIART_THOMAS>::edge_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1199 : template LIBMESH_EXPORT void FE<2,RAVIART_THOMAS>::edge_reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1200 :
1201 : template LIBMESH_EXPORT void FE<2,L2_RAVIART_THOMAS>::reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1202 : template LIBMESH_EXPORT void FE<2,L2_RAVIART_THOMAS>::side_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1203 : template LIBMESH_EXPORT void FE<2,L2_RAVIART_THOMAS>::edge_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1204 : template LIBMESH_EXPORT void FE<2,L2_RAVIART_THOMAS>::edge_reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1205 :
1206 : template LIBMESH_EXPORT void FE<3,NEDELEC_ONE>::reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1207 : template LIBMESH_EXPORT void FE<3,NEDELEC_ONE>::side_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1208 : template LIBMESH_EXPORT void FE<3,NEDELEC_ONE>::edge_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1209 : template LIBMESH_EXPORT void FE<3,NEDELEC_ONE>::edge_reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1210 :
1211 : template LIBMESH_EXPORT void FE<3,RAVIART_THOMAS>::reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1212 : template LIBMESH_EXPORT void FE<3,RAVIART_THOMAS>::side_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1213 : template LIBMESH_EXPORT void FE<3,RAVIART_THOMAS>::edge_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1214 : template LIBMESH_EXPORT void FE<3,RAVIART_THOMAS>::edge_reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1215 :
1216 : template LIBMESH_EXPORT void FE<3,L2_RAVIART_THOMAS>::reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1217 : template LIBMESH_EXPORT void FE<3,L2_RAVIART_THOMAS>::side_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1218 : template LIBMESH_EXPORT void FE<3,L2_RAVIART_THOMAS>::edge_map(Elem const *, Elem const *, const unsigned int, const std::vector<Point> &, std::vector<Point> &);
1219 : template LIBMESH_EXPORT void FE<3,L2_RAVIART_THOMAS>::edge_reinit(Elem const *, unsigned int, Real, const std::vector<Point> * const, const std::vector<Real> * const);
1220 :
1221 : // Intel 9.1 complained it needed this in devel mode.
1222 : //template LIBMESH_EXPORT void FE<2,XYZ>::init_face_shape_functions(const std::vector<Point> &, const Elem *);
1223 : //template LIBMESH_EXPORT void FE<3,XYZ>::init_face_shape_functions(const std::vector<Point> &, const Elem *);
1224 :
1225 : } // namespace libMesh
|