libMesh
fe_map.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 
19 
20 // Local includes
21 #include "libmesh/fe.h"
22 #include "libmesh/elem.h"
23 #include "libmesh/libmesh_logging.h"
24 #include "libmesh/fe_interface.h"
25 #include "libmesh/fe_macro.h"
26 #include "libmesh/fe_map.h"
27 #include "libmesh/fe_xyz_map.h"
28 #include "libmesh/inf_fe_map.h"
29 #include "libmesh/mesh_subdivision_support.h"
30 #include "libmesh/dense_matrix.h"
31 #include "libmesh/dense_vector.h"
32 #include "libmesh/tensor_value.h"
33 #include "libmesh/enum_elem_type.h"
34 #include "libmesh/int_range.h"
35 
36 // C++ includes
37 #include <cstdlib> // *must* precede <cmath> for proper std:abs() on PGI, Sun Studio CC
38 #include <cmath> // for std::sqrt, std::abs
39 #include <memory>
40 
41 namespace libMesh
42 {
44 
46 FEMap::map_fe_type(const Elem & elem)
47 {
48  switch (elem.mapping_type())
49  {
51  return RATIONAL_BERNSTEIN;
52  case LAGRANGE_MAP:
53  return LAGRANGE;
54  default:
55  libmesh_error_msg("Unknown mapping type " << elem.mapping_type());
56  }
57  return LAGRANGE;
58 }
59 
60 
61 
62 // Constructor
64  calculations_started(false),
65  calculate_xyz(false),
66  calculate_dxyz(false),
67 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
68  calculate_d2xyz(false),
69 #endif
70  jacobian_tolerance(jtol)
71 {}
72 
73 
74 
75 std::unique_ptr<FEMap> FEMap::build( FEType fe_type )
76 {
77  switch( fe_type.family )
78  {
79  case XYZ:
80  return std::make_unique<FEXYZMap>();
81 
82  default:
83  return std::make_unique<FEMap>();
84  }
85 }
86 
87 
88 
90 {
91  this->calculations_started = false;
92  this->phi_map.clear();
93  this->dphidxi_map.clear();
94  this->dphideta_map.clear();
95  this->dphidzeta_map.clear();
96 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
97  this->d2phidxi2_map.clear();
98  this->d2phidxideta_map.clear();
99  this->d2phideta2_map.clear();
100  this->d2phidxidzeta_map.clear();
101  this->d2phidetadzeta_map.clear();
102  this->d2phidzeta2_map.clear();
103 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
104 }
105 
106 
107 
108 template<unsigned int Dim>
109 void FEMap::init_reference_to_physical_map(const std::vector<Point> & qp,
110  const Elem * elem)
111 {
112  // Start logging the reference->physical map initialization
113  LOG_SCOPE("init_reference_to_physical_map()", "FEMap");
114 
115  // We're calculating now!
116  this->determine_calculations();
117 
118  // The number of quadrature points.
119  const std::size_t n_qp = qp.size();
120 
121  // The element type and order to use in
122  // the map
123  const FEFamily mapping_family = FEMap::map_fe_type(*elem);
124  const FEType map_fe_type(elem->default_order(), mapping_family);
125 
126  // Number of shape functions used to construct the map
127  // (Lagrange shape functions are used for mapping)
128  // Do not consider the Elem::p_level(), if any, when computing the
129  // number of shape functions.
130  const unsigned int n_mapping_shape_functions =
131  FEInterface::n_shape_functions (map_fe_type, /*extra_order=*/0, elem);
132 
133  // Maybe we already have correctly-sized data? Check data sizes,
134  // and get ready to break out of a "loop" if all these resize()
135  // calls are redundant.
136  unsigned int old_n_qp = 0;
137 
138  do
139  {
140  if (calculate_xyz)
141  {
142  if (this->phi_map.size() == n_mapping_shape_functions)
143  {
144  old_n_qp = n_mapping_shape_functions ? this->phi_map[0].size() : 0;
145  break;
146  }
147  this->phi_map.resize (n_mapping_shape_functions);
148  }
149  if (Dim > 0)
150  {
151  if (calculate_dxyz)
152  {
153  if (this->dphidxi_map.size() == n_mapping_shape_functions)
154  {
155  old_n_qp = n_mapping_shape_functions ? this->dphidxi_map[0].size() : 0;
156  break;
157  }
158  this->dphidxi_map.resize (n_mapping_shape_functions);
159  }
160 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
161  // Don't waste time considering early break here; if we
162  // asked for d2xyz then we surely asked for dxyz too and
163  // considered early break above.
164  if (calculate_d2xyz)
165  this->d2phidxi2_map.resize (n_mapping_shape_functions);
166 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
167  }
168 
169  if (Dim > 1)
170  {
171  if (calculate_dxyz)
172  this->dphideta_map.resize (n_mapping_shape_functions);
173 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
174  if (calculate_d2xyz)
175  {
176  this->d2phidxideta_map.resize (n_mapping_shape_functions);
177  this->d2phideta2_map.resize (n_mapping_shape_functions);
178  }
179 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
180  }
181 
182  if (Dim > 2)
183  {
184  if (calculate_dxyz)
185  this->dphidzeta_map.resize (n_mapping_shape_functions);
186 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
187  if (calculate_d2xyz)
188  {
189  this->d2phidxidzeta_map.resize (n_mapping_shape_functions);
190  this->d2phidetadzeta_map.resize (n_mapping_shape_functions);
191  this->d2phidzeta2_map.resize (n_mapping_shape_functions);
192  }
193 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
194  }
195  }
196  while (false);
197 
198  if (old_n_qp != n_qp)
199  for (unsigned int i=0; i<n_mapping_shape_functions; i++)
200  {
201  if (calculate_xyz)
202  this->phi_map[i].resize (n_qp);
203  if (Dim > 0)
204  {
205  if (calculate_dxyz)
206  this->dphidxi_map[i].resize (n_qp);
207 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
208  if (calculate_d2xyz)
209  {
210  this->d2phidxi2_map[i].resize (n_qp);
211  if (Dim > 1)
212  {
213  this->d2phidxideta_map[i].resize (n_qp);
214  this->d2phideta2_map[i].resize (n_qp);
215  }
216  if (Dim > 2)
217  {
218  this->d2phidxidzeta_map[i].resize (n_qp);
219  this->d2phidetadzeta_map[i].resize (n_qp);
220  this->d2phidzeta2_map[i].resize (n_qp);
221  }
222  }
223 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
224 
225  if (Dim > 1 && calculate_dxyz)
226  this->dphideta_map[i].resize (n_qp);
227 
228  if (Dim > 2 && calculate_dxyz)
229  this->dphidzeta_map[i].resize (n_qp);
230  }
231  }
232 
233  // Optimize for the *linear* geometric elements case:
234  bool is_linear = elem->is_linear();
235 
236  FEInterface::shape_deriv_ptr shape_deriv_ptr =
238 
239 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
240  FEInterface::shape_second_deriv_ptr shape_second_deriv_ptr =
242 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
243 
244  if (calculate_xyz)
245  FEInterface::all_shapes(Dim, map_fe_type, elem, qp, this->phi_map, false);
246 
247  switch (Dim)
248  {
249  //------------------------------------------------------------
250  // 0D
251  case 0:
252  {
253  // No mapping derivatives here
254  break;
255  }
256 
257  //------------------------------------------------------------
258  // 1D
259  case 1:
260  {
261  // Compute gradients of mapping shape functions i at quadrature points p
262 
263  // TODO: optimizations for the RATIONAL_BERNSTEIN+linear case
264  if (is_linear)
265  {
266  for (unsigned int i=0; i<n_mapping_shape_functions; i++)
267  {
268  if (calculate_dxyz)
269  {
270  this->dphidxi_map[i][0] =
271  shape_deriv_ptr(map_fe_type, elem, i, 0, qp[0], false);
272  for (std::size_t p=1; p<n_qp; p++)
273  this->dphidxi_map[i][p] = this->dphidxi_map[i][0];
274  }
275 
276 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
277  if (calculate_d2xyz)
278  {
279  this->d2phidxi2_map[i][0] =
280  shape_second_deriv_ptr(map_fe_type, elem, i, 0, qp[0], false);
281  for (std::size_t p=1; p<n_qp; p++)
282  this->d2phidxi2_map[i][p] = this->d2phidxi2_map[i][0];
283  }
284 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
285  }
286  }
287  else
288  {
289  if (calculate_dxyz)
290  {
291  std::vector<std::vector<Real>> * comps[3]
292  { &this->dphidxi_map, &this->dphideta_map, &this->dphidzeta_map };
293  FEInterface::all_shape_derivs(Dim, map_fe_type, elem, qp, comps, false);
294  }
295 
296 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
297  if (calculate_d2xyz)
298  for (unsigned int i=0; i<n_mapping_shape_functions; i++)
299  for (std::size_t p=0; p<n_qp; p++)
300  this->d2phidxi2_map[i][p] = shape_second_deriv_ptr (map_fe_type, elem, i, 0, qp[p], false);
301 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
302  }
303 
304  break;
305  }
306  //------------------------------------------------------------
307  // 2D
308  case 2:
309  {
310  // Compute gradients of mapping shape functions i at quadrature points p
311 
312  // TODO: optimizations for the RATIONAL_BERNSTEIN+linear case
313  if (is_linear)
314  {
315  for (unsigned int i=0; i<n_mapping_shape_functions; i++)
316  {
317  if (calculate_dxyz)
318  {
319  this->dphidxi_map[i][0] = shape_deriv_ptr (map_fe_type, elem, i, 0, qp[0], false);
320  this->dphideta_map[i][0] = shape_deriv_ptr (map_fe_type, elem, i, 1, qp[0], false);
321  for (std::size_t p=1; p<n_qp; p++)
322  {
323  this->dphidxi_map[i][p] = this->dphidxi_map[i][0];
324  this->dphideta_map[i][p] = this->dphideta_map[i][0];
325  }
326  }
327 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
328  if (calculate_d2xyz)
329  {
330  this->d2phidxi2_map[i][0] = shape_second_deriv_ptr (map_fe_type, elem, i, 0, qp[0], false);
331  this->d2phidxideta_map[i][0] = shape_second_deriv_ptr (map_fe_type, elem, i, 1, qp[0], false);
332  this->d2phideta2_map[i][0] = shape_second_deriv_ptr (map_fe_type, elem, i, 2, qp[0], false);
333  for (std::size_t p=1; p<n_qp; p++)
334  {
335  this->d2phidxi2_map[i][p] = this->d2phidxi2_map[i][0];
336  this->d2phidxideta_map[i][p] = this->d2phidxideta_map[i][0];
337  this->d2phideta2_map[i][p] = this->d2phideta2_map[i][0];
338  }
339  }
340 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
341  }
342  }
343  else
344  {
345  if (calculate_dxyz)
346  {
347  std::vector<std::vector<Real>> * comps[3]
348  { &this->dphidxi_map, &this->dphideta_map, &this->dphidzeta_map };
349  FEInterface::all_shape_derivs(Dim, map_fe_type, elem, qp, comps, false);
350  }
351 
352 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
353  if (calculate_d2xyz)
354  for (unsigned int i=0; i<n_mapping_shape_functions; i++)
355  for (std::size_t p=0; p<n_qp; p++)
356  {
357  this->d2phidxi2_map[i][p] = shape_second_deriv_ptr (map_fe_type, elem, i, 0, qp[p], false);
358  this->d2phidxideta_map[i][p] = shape_second_deriv_ptr (map_fe_type, elem, i, 1, qp[p], false);
359  this->d2phideta2_map[i][p] = shape_second_deriv_ptr (map_fe_type, elem, i, 2, qp[p], false);
360  }
361 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
362  }
363 
364  break;
365  }
366 
367  //------------------------------------------------------------
368  // 3D
369  case 3:
370  {
371  // Compute gradients of mapping shape functions i at quadrature points p
372 
373  // TODO: optimizations for the RATIONAL_BERNSTEIN+linear case
374  if (is_linear)
375  {
376  for (unsigned int i=0; i<n_mapping_shape_functions; i++)
377  {
378  if (calculate_dxyz)
379  {
380  this->dphidxi_map[i][0] = shape_deriv_ptr (map_fe_type, elem, i, 0, qp[0], false);
381  this->dphideta_map[i][0] = shape_deriv_ptr (map_fe_type, elem, i, 1, qp[0], false);
382  this->dphidzeta_map[i][0] = shape_deriv_ptr (map_fe_type, elem, i, 2, qp[0], false);
383 
384  for (std::size_t p=1; p<n_qp; p++)
385  {
386  this->dphidxi_map[i][p] = this->dphidxi_map[i][0];
387  this->dphideta_map[i][p] = this->dphideta_map[i][0];
388  this->dphidzeta_map[i][p] = this->dphidzeta_map[i][0];
389  }
390  }
391 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
392  if (calculate_d2xyz)
393  {
394  this->d2phidxi2_map[i][0] = shape_second_deriv_ptr (map_fe_type, elem, i, 0, qp[0], false);
395  this->d2phidxideta_map[i][0] = shape_second_deriv_ptr (map_fe_type, elem, i, 1, qp[0], false);
396  this->d2phideta2_map[i][0] = shape_second_deriv_ptr (map_fe_type, elem, i, 2, qp[0], false);
397  this->d2phidxidzeta_map[i][0] = shape_second_deriv_ptr (map_fe_type, elem, i, 3, qp[0], false);
398  this->d2phidetadzeta_map[i][0] = shape_second_deriv_ptr (map_fe_type, elem, i, 4, qp[0], false);
399  this->d2phidzeta2_map[i][0] = shape_second_deriv_ptr (map_fe_type, elem, i, 5, qp[0], false);
400 
401  for (std::size_t p=1; p<n_qp; p++)
402  {
403  this->d2phidxi2_map[i][p] = this->d2phidxi2_map[i][0];
404  this->d2phidxideta_map[i][p] = this->d2phidxideta_map[i][0];
405  this->d2phideta2_map[i][p] = this->d2phideta2_map[i][0];
406  this->d2phidxidzeta_map[i][p] = this->d2phidxidzeta_map[i][0];
407  this->d2phidetadzeta_map[i][p] = this->d2phidetadzeta_map[i][0];
408  this->d2phidzeta2_map[i][p] = this->d2phidzeta2_map[i][0];
409  }
410  }
411 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
412  }
413  }
414  else
415  {
416  if (calculate_dxyz)
417  {
418  std::vector<std::vector<Real>> * comps[3]
419  { &this->dphidxi_map, &this->dphideta_map, &this->dphidzeta_map };
420  FEInterface::all_shape_derivs(Dim, map_fe_type, elem, qp, comps, false);
421  }
422 
423 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
424  if (calculate_d2xyz)
425  for (unsigned int i=0; i<n_mapping_shape_functions; i++)
426  for (std::size_t p=0; p<n_qp; p++)
427  {
428  this->d2phidxi2_map[i][p] = shape_second_deriv_ptr (map_fe_type, elem, i, 0, qp[p], false);
429  this->d2phidxideta_map[i][p] = shape_second_deriv_ptr (map_fe_type, elem, i, 1, qp[p], false);
430  this->d2phideta2_map[i][p] = shape_second_deriv_ptr (map_fe_type, elem, i, 2, qp[p], false);
431  this->d2phidxidzeta_map[i][p] = shape_second_deriv_ptr (map_fe_type, elem, i, 3, qp[p], false);
432  this->d2phidetadzeta_map[i][p] = shape_second_deriv_ptr (map_fe_type, elem, i, 4, qp[p], false);
433  this->d2phidzeta2_map[i][p] = shape_second_deriv_ptr (map_fe_type, elem, i, 5, qp[p], false);
434  }
435 #endif // ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
436  }
437 
438  break;
439  }
440 
441  default:
442  libmesh_error_msg("Invalid Dim = " << Dim);
443  }
444 }
445 
446 
447 
448 void FEMap::compute_single_point_map(const unsigned int dim,
449  const std::vector<Real> & qw,
450  const Elem * elem,
451  unsigned int p,
452  const std::vector<const Node *> & elem_nodes,
453  bool compute_second_derivatives)
454 {
455  libmesh_assert(elem);
457 #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES
458  libmesh_assert(!compute_second_derivatives);
459 #endif
460 
461  // this parameter is only accounted for if LIBMESH_DIM==2.
462  libmesh_ignore(compute_second_derivatives);
463 
464  if (calculate_xyz)
465  libmesh_assert_equal_to(phi_map.size(), elem_nodes.size());
466 
467  auto check_for_degenerate_map =
468  [this, elem, p]
469  (Real det_J) {
470  if (det_J <= jacobian_tolerance)
471  {
472  // Don't call get_info() recursively if we're already
473  // failing. get_info() calls Elem::volume() which may
474  // call FE::reinit() and trigger the same failure again.
475  static bool failing = false;
476  if (!failing)
477  {
478  failing = true;
479  std::string elem_info = elem->get_info();
480  failing = false;
481  if (calculate_xyz)
482  {
483  libmesh_degenerate_mapping_msg
484  ("Jacobian " << det_J << " at or under tolerance " <<
485  jacobian_tolerance << " at point " << xyz[p] <<
486  " in element:\n" << elem_info);
487  }
488  else
489  {
490  // In this case xyz[p] is not defined, so don't
491  // try to print it out.
492  libmesh_degenerate_mapping_msg
493  ("Jacobian " << det_J << " at or under tolerance " <<
494  jacobian_tolerance << " at point index " << p <<
495  " in element:\n" << elem_info);
496  }
497  }
498  else
499  {
500  // We were already failing when we called this, so just
501  // stop the current computation and return with
502  // incomplete results.
503  return;
504  }
505  }
506  };
507 
508  switch (dim)
509  {
510  //--------------------------------------------------------------------
511  // 0D
512  case 0:
513  {
514  libmesh_assert(elem_nodes[0]);
515  if (calculate_xyz)
516  xyz[p] = *elem_nodes[0];
517  if (calculate_dxyz)
518  {
519  jac[p] = 1.0;
520  JxW[p] = qw[p];
521  }
522  break;
523  }
524 
525  //--------------------------------------------------------------------
526  // 1D
527  case 1:
528  {
529  // Clear the entities that will be summed
530  if (calculate_xyz)
531  xyz[p].zero();
532  if (calculate_dxyz)
533  dxyzdxi_map[p].zero();
534 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
535  if (calculate_d2xyz)
536  {
537  d2xyzdxi2_map[p].zero();
538  // Inverse map second derivatives
539  d2xidxyz2_map[p].assign(6, 0.);
540  }
541 #endif
542 
543  // compute x, dx, d2x at the quadrature point
544  for (auto i : index_range(elem_nodes)) // sum over the nodes
545  {
546  // Reference to the point, helps eliminate
547  // excessive temporaries in the inner loop
548  libmesh_assert(elem_nodes[i]);
549  const Point & elem_point = *elem_nodes[i];
550 
551  if (calculate_xyz)
552  xyz[p].add_scaled (elem_point, phi_map[i][p] );
553  if (calculate_dxyz)
554  dxyzdxi_map[p].add_scaled (elem_point, dphidxi_map[i][p]);
555 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
556  if (calculate_d2xyz)
557  d2xyzdxi2_map[p].add_scaled(elem_point, d2phidxi2_map[i][p]);
558 #endif
559  }
560 
561  // Compute the jacobian
562  //
563  // 1D elements can live in 2D or 3D space.
564  // The transformation matrix from local->global
565  // coordinates is
566  //
567  // T = | dx/dxi |
568  // | dy/dxi |
569  // | dz/dxi |
570  //
571  // The generalized determinant of T (from the
572  // so-called "normal" eqns.) is
573  // jac = "det(T)" = sqrt(det(T'T))
574  //
575  // where T'= transpose of T, so
576  //
577  // jac = sqrt( (dx/dxi)^2 + (dy/dxi)^2 + (dz/dxi)^2 )
578 
579  if (calculate_dxyz)
580  {
581  jac[p] = dxyzdxi_map[p].norm();
582 
583  check_for_degenerate_map(jac[p]);
584 
585  // The inverse Jacobian entries also come from the
586  // generalized inverse of T (see also the 2D element
587  // living in 3D code).
588  const Real jacm2 = 1./jac[p]/jac[p];
589  dxidx_map[p] = jacm2*dxdxi_map(p);
590 #if LIBMESH_DIM > 1
591  dxidy_map[p] = jacm2*dydxi_map(p);
592 #endif
593 #if LIBMESH_DIM > 2
594  dxidz_map[p] = jacm2*dzdxi_map(p);
595 #endif
596 
597  JxW[p] = jac[p]*qw[p];
598  }
599 
600 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
601 
602  if (calculate_d2xyz)
603  {
604 #if LIBMESH_DIM == 1
605  // Compute inverse map second derivatives for 1D-element-living-in-1D case
607 #elif LIBMESH_DIM == 2
608  // Compute inverse map second derivatives for 1D-element-living-in-2D case
609  // See JWP notes for details
610 
611  // numer = x_xi*x_{xi xi} + y_xi*y_{xi xi}
612  Real numer =
613  dxyzdxi_map[p](0)*d2xyzdxi2_map[p](0) +
614  dxyzdxi_map[p](1)*d2xyzdxi2_map[p](1);
615 
616  // denom = (x_xi)^2 + (y_xi)^2 must be >= 0.0
617  Real denom =
618  dxyzdxi_map[p](0)*dxyzdxi_map[p](0) +
619  dxyzdxi_map[p](1)*dxyzdxi_map[p](1);
620 
621  if (denom <= 0.0)
622  {
623  // Don't call print_info() recursively if we're already
624  // failing. print_info() calls Elem::volume() which may
625  // call FE::reinit() and trigger the same failure again.
626  static bool failing = false;
627  if (!failing)
628  {
629  failing = true;
630  elem->print_info(libMesh::err);
631  failing = false;
632  libmesh_error_msg("Encountered invalid 1D element!");
633  }
634  else
635  {
636  // We were already failing when we called this, so just
637  // stop the current computation and return with
638  // incomplete results.
639  return;
640  }
641  }
642 
643  // xi_{x x}
644  d2xidxyz2_map[p][0] = -numer * dxidx_map[p]*dxidx_map[p] / denom;
645 
646  // xi_{x y}
647  d2xidxyz2_map[p][1] = -numer * dxidx_map[p]*dxidy_map[p] / denom;
648 
649  // xi_{y y}
650  d2xidxyz2_map[p][3] = -numer * dxidy_map[p]*dxidy_map[p] / denom;
651 
652 #elif LIBMESH_DIM == 3
653  // Compute inverse map second derivatives for 1D-element-living-in-3D case
654  // See JWP notes for details
655 
656  // numer = x_xi*x_{xi xi} + y_xi*y_{xi xi} + z_xi*z_{xi xi}
657  Real numer =
658  dxyzdxi_map[p](0)*d2xyzdxi2_map[p](0) +
659  dxyzdxi_map[p](1)*d2xyzdxi2_map[p](1) +
660  dxyzdxi_map[p](2)*d2xyzdxi2_map[p](2);
661 
662  // denom = (x_xi)^2 + (y_xi)^2 + (z_xi)^2 must be >= 0.0
663  Real denom =
664  dxyzdxi_map[p](0)*dxyzdxi_map[p](0) +
665  dxyzdxi_map[p](1)*dxyzdxi_map[p](1) +
666  dxyzdxi_map[p](2)*dxyzdxi_map[p](2);
667 
668  if (denom <= 0.0)
669  {
670  // Don't call print_info() recursively if we're already
671  // failing. print_info() calls Elem::volume() which may
672  // call FE::reinit() and trigger the same failure again.
673  static bool failing = false;
674  if (!failing)
675  {
676  failing = true;
677  elem->print_info(libMesh::err);
678  failing = false;
679  libmesh_error_msg("Encountered invalid 1D element!");
680  }
681  else
682  {
683  // We were already failing when we called this, so just
684  // stop the current computation and return with
685  // incomplete results.
686  return;
687  }
688  }
689 
690  // xi_{x x}
691  d2xidxyz2_map[p][0] = -numer * dxidx_map[p]*dxidx_map[p] / denom;
692 
693  // xi_{x y}
694  d2xidxyz2_map[p][1] = -numer * dxidx_map[p]*dxidy_map[p] / denom;
695 
696  // xi_{x z}
697  d2xidxyz2_map[p][2] = -numer * dxidx_map[p]*dxidz_map[p] / denom;
698 
699  // xi_{y y}
700  d2xidxyz2_map[p][3] = -numer * dxidy_map[p]*dxidy_map[p] / denom;
701 
702  // xi_{y z}
703  d2xidxyz2_map[p][4] = -numer * dxidy_map[p]*dxidz_map[p] / denom;
704 
705  // xi_{z z}
706  d2xidxyz2_map[p][5] = -numer * dxidz_map[p]*dxidz_map[p] / denom;
707 #endif //LIBMESH_DIM == 3
708  } // calculate_d2xyz
709 
710 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
711 
712  // done computing the map
713  break;
714  }
715 
716 
717  //--------------------------------------------------------------------
718  // 2D
719  case 2:
720  {
721  //------------------------------------------------------------------
722  // Compute the (x,y) values at the quadrature points,
723  // the Jacobian at the quadrature points
724 
725  if (calculate_xyz)
726  xyz[p].zero();
727 
728  if (calculate_dxyz)
729  {
730  dxyzdxi_map[p].zero();
731  dxyzdeta_map[p].zero();
732  }
733 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
734  if (calculate_d2xyz)
735  {
736  d2xyzdxi2_map[p].zero();
737  d2xyzdxideta_map[p].zero();
738  d2xyzdeta2_map[p].zero();
739  // Inverse map second derivatives
740  d2xidxyz2_map[p].assign(6, 0.);
741  d2etadxyz2_map[p].assign(6, 0.);
742  }
743 #endif
744 
745 
746  // compute (x,y) at the quadrature points, derivatives once
747  for (auto i : index_range(elem_nodes)) // sum over the nodes
748  {
749  // Reference to the point, helps eliminate
750  // excessive temporaries in the inner loop
751  libmesh_assert(elem_nodes[i]);
752  const Point & elem_point = *elem_nodes[i];
753 
754  if (calculate_xyz)
755  xyz[p].add_scaled (elem_point, phi_map[i][p] );
756 
757  if (calculate_dxyz)
758  {
759  dxyzdxi_map[p].add_scaled (elem_point, dphidxi_map[i][p] );
760  dxyzdeta_map[p].add_scaled (elem_point, dphideta_map[i][p]);
761  }
762 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
763  if (calculate_d2xyz)
764  {
765  d2xyzdxi2_map[p].add_scaled (elem_point, d2phidxi2_map[i][p]);
766  d2xyzdxideta_map[p].add_scaled (elem_point, d2phidxideta_map[i][p]);
767  d2xyzdeta2_map[p].add_scaled (elem_point, d2phideta2_map[i][p]);
768  }
769 #endif
770  }
771 
772  if (calculate_dxyz)
773  {
774  // compute the jacobian once
775  const Real dx_dxi = dxdxi_map(p),
776  dx_deta = dxdeta_map(p),
777  dy_dxi = dydxi_map(p),
778  dy_deta = dydeta_map(p);
779 
780 #if LIBMESH_DIM == 2
781  // Compute the Jacobian. This assumes the 2D face
782  // lives in 2D space
783  //
784  // Symbolically, the matrix determinant is
785  //
786  // | dx/dxi dx/deta |
787  // jac = | dy/dxi dy/deta |
788  //
789  // jac = dx/dxi*dy/deta - dx/deta*dy/dxi
790  jac[p] = (dx_dxi*dy_deta - dx_deta*dy_dxi);
791 
792  check_for_degenerate_map(jac[p]);
793 
794  JxW[p] = jac[p]*qw[p];
795 
796  // Compute the shape function derivatives wrt x,y at the
797  // quadrature points
798  const Real inv_jac = 1./jac[p];
799 
800  dxidx_map[p] = dy_deta*inv_jac; //dxi/dx = (1/J)*dy/deta
801  dxidy_map[p] = -dx_deta*inv_jac; //dxi/dy = -(1/J)*dx/deta
802  detadx_map[p] = -dy_dxi* inv_jac; //deta/dx = -(1/J)*dy/dxi
803  detady_map[p] = dx_dxi* inv_jac; //deta/dy = (1/J)*dx/dxi
804 
805  dxidz_map[p] = detadz_map[p] = 0.;
806 
807 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
808  if (compute_second_derivatives)
810 #endif
811 #else // LIBMESH_DIM == 3
812 
813  const Real dz_dxi = dzdxi_map(p),
814  dz_deta = dzdeta_map(p);
815 
816  // Compute the Jacobian. This assumes a 2D face in
817  // 3D space.
818  //
819  // The transformation matrix T from local to global
820  // coordinates is
821  //
822  // | dx/dxi dx/deta |
823  // T = | dy/dxi dy/deta |
824  // | dz/dxi dz/deta |
825  // note det(T' T) = det(T')det(T) = det(T)det(T)
826  // so det(T) = std::sqrt(det(T' T))
827  //
828  //----------------------------------------------
829  // Notes:
830  //
831  // dX = R dXi -> R'dX = R'R dXi
832  // (R^-1)dX = dXi [(R'R)^-1 R']dX = dXi
833  //
834  // so R^-1 = (R'R)^-1 R'
835  //
836  // and R^-1 R = (R'R)^-1 R'R = I.
837  //
838  const Real g11 = (dx_dxi*dx_dxi +
839  dy_dxi*dy_dxi +
840  dz_dxi*dz_dxi);
841 
842  const Real g12 = (dx_dxi*dx_deta +
843  dy_dxi*dy_deta +
844  dz_dxi*dz_deta);
845 
846  const Real g21 = g12;
847 
848  const Real g22 = (dx_deta*dx_deta +
849  dy_deta*dy_deta +
850  dz_deta*dz_deta);
851 
852  const Real det = (g11*g22 - g12*g21);
853 
854  check_for_degenerate_map(det);
855 
856  const Real inv_det = 1./det;
857  jac[p] = std::sqrt(det);
858 
859  JxW[p] = jac[p]*qw[p];
860 
861  const Real g11inv = g22*inv_det;
862  const Real g12inv = -g12*inv_det;
863  const Real g21inv = -g21*inv_det;
864  const Real g22inv = g11*inv_det;
865 
866  dxidx_map[p] = g11inv*dx_dxi + g12inv*dx_deta;
867  dxidy_map[p] = g11inv*dy_dxi + g12inv*dy_deta;
868  dxidz_map[p] = g11inv*dz_dxi + g12inv*dz_deta;
869 
870  detadx_map[p] = g21inv*dx_dxi + g22inv*dx_deta;
871  detady_map[p] = g21inv*dy_dxi + g22inv*dy_deta;
872  detadz_map[p] = g21inv*dz_dxi + g22inv*dz_deta;
873 
874 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
875 
876  if (calculate_d2xyz)
877  {
878  // Compute inverse map second derivative values for
879  // 2D-element-living-in-3D case. We pursue a least-squares
880  // solution approach for this "non-square" case, see JWP notes
881  // for details.
882 
883  // A = [ x_{xi xi} x_{eta eta} ]
884  // [ y_{xi xi} y_{eta eta} ]
885  // [ z_{xi xi} z_{eta eta} ]
886  DenseMatrix<Real> A(3,2);
887  A(0,0) = d2xyzdxi2_map[p](0); A(0,1) = d2xyzdeta2_map[p](0);
888  A(1,0) = d2xyzdxi2_map[p](1); A(1,1) = d2xyzdeta2_map[p](1);
889  A(2,0) = d2xyzdxi2_map[p](2); A(2,1) = d2xyzdeta2_map[p](2);
890 
891  // J^T, the transpose of the Jacobian matrix
892  DenseMatrix<Real> JT(2,3);
893  JT(0,0) = dx_dxi; JT(0,1) = dy_dxi; JT(0,2) = dz_dxi;
894  JT(1,0) = dx_deta; JT(1,1) = dy_deta; JT(1,2) = dz_deta;
895 
896  // (J^T J)^(-1), this has already been computed for us above...
897  DenseMatrix<Real> JTJinv(2,2);
898  JTJinv(0,0) = g11inv; JTJinv(0,1) = g12inv;
899  JTJinv(1,0) = g21inv; JTJinv(1,1) = g22inv;
900 
901  // Some helper variables
903  dxi (dxidx_map[p], dxidy_map[p], dxidz_map[p]),
904  deta (detadx_map[p], detady_map[p], detadz_map[p]);
905 
906  // To be filled in below
907  DenseVector<Real> tmp1(2);
908  DenseVector<Real> tmp2(3);
909  DenseVector<Real> tmp3(2);
910 
911  // For (s,t) in {(x,x), (x,y), (x,z), (y,y), (y,z), (z,z)}, compute the
912  // vector of inverse map second derivatives [xi_{s t}, eta_{s t}]
913  unsigned ctr=0;
914  for (unsigned s=0; s<3; ++s)
915  for (unsigned t=s; t<3; ++t)
916  {
917  // Construct tmp1 = [xi_s*xi_t, eta_s*eta_t]
918  tmp1(0) = dxi(s)*dxi(t);
919  tmp1(1) = deta(s)*deta(t);
920 
921  // Compute tmp2 = A * tmp1
922  A.vector_mult(tmp2, tmp1);
923 
924  // Compute scalar value "alpha"
925  Real alpha = dxi(s)*deta(t) + deta(s)*dxi(t);
926 
927  // Compute tmp2 <- tmp2 + alpha * x_{xi eta}
928  for (unsigned i=0; i<3; ++i)
929  tmp2(i) += alpha*d2xyzdxideta_map[p](i);
930 
931  // Compute tmp3 = J^T * tmp2
932  JT.vector_mult(tmp3, tmp2);
933 
934  // Compute tmp1 = (J^T J)^(-1) * tmp3. tmp1 is available for us to reuse.
935  JTJinv.vector_mult(tmp1, tmp3);
936 
937  // Fill in appropriate entries, don't forget to multiply by -1!
938  d2xidxyz2_map[p][ctr] = -tmp1(0);
939  d2etadxyz2_map[p][ctr] = -tmp1(1);
940 
941  // Increment the counter
942  ctr++;
943  }
944  }
945 
946 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
947 
948 #endif // LIBMESH_DIM == 3
949  }
950  // done computing the map
951  break;
952  }
953 
954 
955 
956  //--------------------------------------------------------------------
957  // 3D
958  case 3:
959  {
960  //------------------------------------------------------------------
961  // Compute the (x,y,z) values at the quadrature points,
962  // the Jacobian at the quadrature point
963 
964  // Clear the entities that will be summed
965  if (calculate_xyz)
966  xyz[p].zero ();
967  if (calculate_dxyz)
968  {
969  dxyzdxi_map[p].zero ();
970  dxyzdeta_map[p].zero ();
971  dxyzdzeta_map[p].zero ();
972  }
973 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
974  if (calculate_d2xyz)
975  {
976  d2xyzdxi2_map[p].zero();
977  d2xyzdxideta_map[p].zero();
978  d2xyzdxidzeta_map[p].zero();
979  d2xyzdeta2_map[p].zero();
980  d2xyzdetadzeta_map[p].zero();
981  d2xyzdzeta2_map[p].zero();
982  // Inverse map second derivatives
983  d2xidxyz2_map[p].assign(6, 0.);
984  d2etadxyz2_map[p].assign(6, 0.);
985  d2zetadxyz2_map[p].assign(6, 0.);
986  }
987 #endif
988 
989 
990  // compute (x,y,z) at the quadrature points,
991  // dxdxi, dydxi, dzdxi,
992  // dxdeta, dydeta, dzdeta,
993  // dxdzeta, dydzeta, dzdzeta all once
994  for (auto i : index_range(elem_nodes)) // sum over the nodes
995  {
996  // Reference to the point, helps eliminate
997  // excessive temporaries in the inner loop
998  libmesh_assert(elem_nodes[i]);
999  const Point & elem_point = *elem_nodes[i];
1000 
1001  if (calculate_xyz)
1002  xyz[p].add_scaled (elem_point, phi_map[i][p] );
1003  if (calculate_dxyz)
1004  {
1005  dxyzdxi_map[p].add_scaled (elem_point, dphidxi_map[i][p] );
1006  dxyzdeta_map[p].add_scaled (elem_point, dphideta_map[i][p] );
1007  dxyzdzeta_map[p].add_scaled (elem_point, dphidzeta_map[i][p]);
1008  }
1009 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1010  if (calculate_d2xyz)
1011  {
1012  d2xyzdxi2_map[p].add_scaled (elem_point,
1013  d2phidxi2_map[i][p]);
1014  d2xyzdxideta_map[p].add_scaled (elem_point,
1015  d2phidxideta_map[i][p]);
1016  d2xyzdxidzeta_map[p].add_scaled (elem_point,
1017  d2phidxidzeta_map[i][p]);
1018  d2xyzdeta2_map[p].add_scaled (elem_point,
1019  d2phideta2_map[i][p]);
1020  d2xyzdetadzeta_map[p].add_scaled (elem_point,
1021  d2phidetadzeta_map[i][p]);
1022  d2xyzdzeta2_map[p].add_scaled (elem_point,
1023  d2phidzeta2_map[i][p]);
1024  }
1025 #endif
1026  }
1027 
1028  if (calculate_dxyz)
1029  {
1030  // compute the jacobian
1031  const Real
1032  dx_dxi = dxdxi_map(p), dy_dxi = dydxi_map(p), dz_dxi = dzdxi_map(p),
1033  dx_deta = dxdeta_map(p), dy_deta = dydeta_map(p), dz_deta = dzdeta_map(p),
1034  dx_dzeta = dxdzeta_map(p), dy_dzeta = dydzeta_map(p), dz_dzeta = dzdzeta_map(p);
1035 
1036  // Symbolically, the matrix determinant is
1037  //
1038  // | dx/dxi dy/dxi dz/dxi |
1039  // jac = | dx/deta dy/deta dz/deta |
1040  // | dx/dzeta dy/dzeta dz/dzeta |
1041  //
1042  // jac = dx/dxi*(dy/deta*dz/dzeta - dz/deta*dy/dzeta) +
1043  // dy/dxi*(dz/deta*dx/dzeta - dx/deta*dz/dzeta) +
1044  // dz/dxi*(dx/deta*dy/dzeta - dy/deta*dx/dzeta)
1045 
1046  jac[p] = (dx_dxi*(dy_deta*dz_dzeta - dz_deta*dy_dzeta) +
1047  dy_dxi*(dz_deta*dx_dzeta - dx_deta*dz_dzeta) +
1048  dz_dxi*(dx_deta*dy_dzeta - dy_deta*dx_dzeta));
1049 
1050  check_for_degenerate_map(jac[p]);
1051 
1052  JxW[p] = jac[p]*qw[p];
1053 
1054  // Compute the shape function derivatives wrt x,y at the
1055  // quadrature points
1056  const Real inv_jac = 1./jac[p];
1057 
1058  dxidx_map[p] = (dy_deta*dz_dzeta - dz_deta*dy_dzeta)*inv_jac;
1059  dxidy_map[p] = (dz_deta*dx_dzeta - dx_deta*dz_dzeta)*inv_jac;
1060  dxidz_map[p] = (dx_deta*dy_dzeta - dy_deta*dx_dzeta)*inv_jac;
1061 
1062  detadx_map[p] = (dz_dxi*dy_dzeta - dy_dxi*dz_dzeta )*inv_jac;
1063  detady_map[p] = (dx_dxi*dz_dzeta - dz_dxi*dx_dzeta )*inv_jac;
1064  detadz_map[p] = (dy_dxi*dx_dzeta - dx_dxi*dy_dzeta )*inv_jac;
1065 
1066  dzetadx_map[p] = (dy_dxi*dz_deta - dz_dxi*dy_deta )*inv_jac;
1067  dzetady_map[p] = (dz_dxi*dx_deta - dx_dxi*dz_deta )*inv_jac;
1068  dzetadz_map[p] = (dx_dxi*dy_deta - dy_dxi*dx_deta )*inv_jac;
1069  }
1070 
1071 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1072  if (compute_second_derivatives)
1074 #endif
1075  // done computing the map
1076  break;
1077  }
1078 
1079  default:
1080  libmesh_error_msg("Invalid dim = " << dim);
1081  }
1082 }
1083 
1084 
1085 
1086 void FEMap::resize_quadrature_map_vectors(const unsigned int dim, unsigned int n_qp)
1087 {
1088  // We're calculating now!
1089  this->determine_calculations();
1090 
1091  // Resize the vectors to hold data at the quadrature points
1092  if (calculate_xyz)
1093  xyz.resize(n_qp);
1094  if (calculate_dxyz)
1095  {
1096  dxyzdxi_map.resize(n_qp);
1097  dxidx_map.resize(n_qp);
1098  dxidy_map.resize(n_qp); // 1D element may live in 2D ...
1099  dxidz_map.resize(n_qp); // ... or 3D
1100  }
1101 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1102  if (calculate_d2xyz)
1103  {
1104  d2xyzdxi2_map.resize(n_qp);
1105 
1106  // Inverse map second derivatives
1107  d2xidxyz2_map.resize(n_qp);
1108  for (auto i : index_range(d2xidxyz2_map))
1109  d2xidxyz2_map[i].assign(6, 0.);
1110  }
1111 #endif
1112  if (dim > 1)
1113  {
1114  if (calculate_dxyz)
1115  {
1116  dxyzdeta_map.resize(n_qp);
1117  detadx_map.resize(n_qp);
1118  detady_map.resize(n_qp);
1119  detadz_map.resize(n_qp);
1120  }
1121 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1122  if (calculate_d2xyz)
1123  {
1124  d2xyzdxideta_map.resize(n_qp);
1125  d2xyzdeta2_map.resize(n_qp);
1126 
1127  // Inverse map second derivatives
1128  d2etadxyz2_map.resize(n_qp);
1129  for (auto i : index_range(d2etadxyz2_map))
1130  d2etadxyz2_map[i].assign(6, 0.);
1131  }
1132 #endif
1133  if (dim > 2)
1134  {
1135  if (calculate_dxyz)
1136  {
1137  dxyzdzeta_map.resize (n_qp);
1138  dzetadx_map.resize (n_qp);
1139  dzetady_map.resize (n_qp);
1140  dzetadz_map.resize (n_qp);
1141  }
1142 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1143  if (calculate_d2xyz)
1144  {
1145  d2xyzdxidzeta_map.resize(n_qp);
1146  d2xyzdetadzeta_map.resize(n_qp);
1147  d2xyzdzeta2_map.resize(n_qp);
1148 
1149  // Inverse map second derivatives
1150  d2zetadxyz2_map.resize(n_qp);
1151  for (auto i : index_range(d2zetadxyz2_map))
1152  d2zetadxyz2_map[i].assign(6, 0.);
1153  }
1154 #endif
1155  }
1156  }
1157 
1158  if (calculate_dxyz)
1159  {
1160  jac.resize(n_qp);
1161  JxW.resize(n_qp);
1162  }
1163 }
1164 
1165 
1166 
1167 void FEMap::compute_affine_map(const unsigned int dim,
1168  const std::vector<Real> & qw,
1169  const Elem * elem)
1170 {
1171  // Start logging the map computation.
1172  LOG_SCOPE("compute_affine_map()", "FEMap");
1173 
1174  libmesh_assert(elem);
1175 
1176  const unsigned int n_qp = cast_int<unsigned int>(qw.size());
1177 
1178  // Resize the vectors to hold data at the quadrature points
1179  this->resize_quadrature_map_vectors(dim, n_qp);
1180 
1181  // Determine the nodes contributing to element elem
1182  unsigned int n_nodes = elem->n_nodes();
1183  _elem_nodes.resize(elem->n_nodes());
1184  for (unsigned int i=0; i<n_nodes; i++)
1185  _elem_nodes[i] = elem->node_ptr(i);
1186 
1187  // Compute map at quadrature point 0
1188  this->compute_single_point_map(dim, qw, elem, 0, _elem_nodes, /*compute_second_derivatives=*/false);
1189 
1190  // Compute xyz at all other quadrature points
1191  if (calculate_xyz)
1192  for (unsigned int p=1; p<n_qp; p++)
1193  {
1194  xyz[p].zero();
1195  for (auto i : index_range(phi_map)) // sum over the nodes
1196  xyz[p].add_scaled (*_elem_nodes[i], phi_map[i][p]);
1197  }
1198 
1199  // Copy other map data from quadrature point 0
1200  if (calculate_dxyz)
1201  for (unsigned int p=1; p<n_qp; p++) // for each extra quadrature point
1202  {
1203  dxyzdxi_map[p] = dxyzdxi_map[0];
1204  dxidx_map[p] = dxidx_map[0];
1205  dxidy_map[p] = dxidy_map[0];
1206  dxidz_map[p] = dxidz_map[0];
1207 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1208  // The map should be affine, so second derivatives are zero
1209  if (calculate_d2xyz)
1210  d2xyzdxi2_map[p] = 0.;
1211 #endif
1212  if (dim > 1)
1213  {
1214  dxyzdeta_map[p] = dxyzdeta_map[0];
1215  detadx_map[p] = detadx_map[0];
1216  detady_map[p] = detady_map[0];
1217  detadz_map[p] = detadz_map[0];
1218 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1219  if (calculate_d2xyz)
1220  {
1221  d2xyzdxideta_map[p] = 0.;
1222  d2xyzdeta2_map[p] = 0.;
1223  }
1224 #endif
1225  if (dim > 2)
1226  {
1227  dxyzdzeta_map[p] = dxyzdzeta_map[0];
1228  dzetadx_map[p] = dzetadx_map[0];
1229  dzetady_map[p] = dzetady_map[0];
1230  dzetadz_map[p] = dzetadz_map[0];
1231 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1232  if (calculate_d2xyz)
1233  {
1234  d2xyzdxidzeta_map[p] = 0.;
1235  d2xyzdetadzeta_map[p] = 0.;
1236  d2xyzdzeta2_map[p] = 0.;
1237  }
1238 #endif
1239  }
1240  }
1241  jac[p] = jac[0];
1242  JxW[p] = JxW[0] / qw[0] * qw[p];
1243  }
1244 }
1245 
1246 
1247 
1248 void FEMap::compute_null_map(const unsigned int dim,
1249  const std::vector<Real> & qw)
1250 {
1251  // Start logging the map computation.
1252  LOG_SCOPE("compute_null_map()", "FEMap");
1253 
1254  const unsigned int n_qp = cast_int<unsigned int>(qw.size());
1255 
1256  // Resize the vectors to hold data at the quadrature points
1257  this->resize_quadrature_map_vectors(dim, n_qp);
1258 
1259  // Compute "fake" xyz
1260  for (unsigned int p=1; p<n_qp; p++)
1261  {
1262  if (calculate_xyz)
1263  xyz[p].zero();
1264 
1265  if (calculate_dxyz)
1266  {
1267  dxyzdxi_map[p] = 0;
1268  dxidx_map[p] = 0;
1269  dxidy_map[p] = 0;
1270  dxidz_map[p] = 0;
1271  }
1272 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1273  if (calculate_d2xyz)
1274  {
1275  d2xyzdxi2_map[p] = 0;
1276  }
1277 #endif
1278  if (dim > 1)
1279  {
1280  if (calculate_dxyz)
1281  {
1282  dxyzdeta_map[p] = 0;
1283  detadx_map[p] = 0;
1284  detady_map[p] = 0;
1285  detadz_map[p] = 0;
1286  }
1287 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1288  if (calculate_d2xyz)
1289  {
1290  d2xyzdxideta_map[p] = 0.;
1291  d2xyzdeta2_map[p] = 0.;
1292  }
1293 #endif
1294  if (dim > 2)
1295  {
1296  if (calculate_dxyz)
1297  {
1298  dxyzdzeta_map[p] = 0;
1299  dzetadx_map[p] = 0;
1300  dzetady_map[p] = 0;
1301  dzetadz_map[p] = 0;
1302  }
1303 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1304  if (calculate_d2xyz)
1305  {
1306  d2xyzdxidzeta_map[p] = 0;
1307  d2xyzdetadzeta_map[p] = 0;
1308  d2xyzdzeta2_map[p] = 0;
1309  }
1310 #endif
1311  }
1312  }
1313  if (calculate_dxyz)
1314  {
1315  jac[p] = 1;
1316  JxW[p] = qw[p];
1317  }
1318  }
1319 }
1320 
1321 
1322 
1323 void FEMap::compute_map(const unsigned int dim,
1324  const std::vector<Real> & qw,
1325  const Elem * elem,
1326  bool calculate_d2phi)
1327 {
1328  if (!elem)
1329  {
1330  compute_null_map(dim, qw);
1331  return;
1332  }
1333 
1334  if (elem->has_affine_map())
1335  {
1336  compute_affine_map(dim, qw, elem);
1337  return;
1338  }
1339 #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES
1340  libmesh_assert(!calculate_d2phi);
1341 #endif
1342 
1343  // Start logging the map computation.
1344  LOG_SCOPE("compute_map()", "FEMap");
1345 
1346  libmesh_assert(elem);
1347 
1348  const unsigned int n_qp = cast_int<unsigned int>(qw.size());
1349 
1350  // Resize the vectors to hold data at the quadrature points
1351  this->resize_quadrature_map_vectors(dim, n_qp);
1352 
1353  // Determine the nodes contributing to element elem
1354  if (elem->type() == TRI3SUBDIVISION)
1355  {
1356  // Subdivision surface FE require the 1-ring around elem
1357  libmesh_assert_equal_to (dim, 2);
1358  const Tri3Subdivision * sd_elem = static_cast<const Tri3Subdivision *>(elem);
1360  }
1361  else
1362  {
1363  // All other FE use only the nodes of elem itself
1364  _elem_nodes.resize(elem->n_nodes(), nullptr);
1365  for (auto i : elem->node_index_range())
1366  _elem_nodes[i] = elem->node_ptr(i);
1367  }
1368 
1369  // Compute map at all quadrature points
1370  for (unsigned int p=0; p!=n_qp; p++)
1371  this->compute_single_point_map(dim, qw, elem, p, _elem_nodes, calculate_d2phi);
1372 }
1373 
1374 
1375 
1376 void FEMap::print_JxW(std::ostream & os) const
1377 {
1378  for (auto i : index_range(JxW))
1379  os << " [" << i << "]: " << JxW[i] << std::endl;
1380 }
1381 
1382 
1383 
1384 void FEMap::print_xyz(std::ostream & os) const
1385 {
1386  for (auto i : index_range(xyz))
1387  os << " [" << i << "]: " << xyz[i];
1388 }
1389 
1390 
1391 
1393 {
1394 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1395  // Only certain second derivatives are valid depending on the
1396  // dimension...
1397  std::set<unsigned> valid_indices;
1398 
1399  // Construct J^{-1}, A, and B matrices (see JWP's notes for details)
1400  // for cases in which the element dimension matches LIBMESH_DIM.
1401 #if LIBMESH_DIM==1
1402  RealTensor
1403  Jinv(dxidx_map[p], 0., 0.,
1404  0., 0., 0.,
1405  0., 0., 0.),
1406 
1407  A(d2xyzdxi2_map[p](0), 0., 0.,
1408  0., 0., 0.,
1409  0., 0., 0.),
1410 
1411  B(0., 0., 0.,
1412  0., 0., 0.,
1413  0., 0., 0.);
1414 
1416  dxi (dxidx_map[p], 0., 0.),
1417  deta (0., 0., 0.),
1418  dzeta(0., 0., 0.);
1419 
1420  // In 1D, we have only the xx second derivative
1421  valid_indices.insert(0);
1422 
1423 #elif LIBMESH_DIM==2
1424  RealTensor
1425  Jinv(dxidx_map[p], dxidy_map[p], 0.,
1426  detadx_map[p], detady_map[p], 0.,
1427  0., 0., 0.),
1428 
1429  A(d2xyzdxi2_map[p](0), d2xyzdeta2_map[p](0), 0.,
1430  d2xyzdxi2_map[p](1), d2xyzdeta2_map[p](1), 0.,
1431  0., 0., 0.),
1432 
1433  B(d2xyzdxideta_map[p](0), 0., 0.,
1434  d2xyzdxideta_map[p](1), 0., 0.,
1435  0., 0., 0.);
1436 
1438  dxi (dxidx_map[p], dxidy_map[p], 0.),
1439  deta (detadx_map[p], detady_map[p], 0.),
1440  dzeta(0., 0., 0.);
1441 
1442  // In 2D, we have xx, xy, and yy second derivatives
1443  const unsigned tmp[3] = {0,1,3};
1444  valid_indices.insert(tmp, tmp+3);
1445 
1446 #elif LIBMESH_DIM==3
1447  RealTensor
1448  Jinv(dxidx_map[p], dxidy_map[p], dxidz_map[p],
1449  detadx_map[p], detady_map[p], detadz_map[p],
1450  dzetadx_map[p], dzetady_map[p], dzetadz_map[p]),
1451 
1452  A(d2xyzdxi2_map[p](0), d2xyzdeta2_map[p](0), d2xyzdzeta2_map[p](0),
1453  d2xyzdxi2_map[p](1), d2xyzdeta2_map[p](1), d2xyzdzeta2_map[p](1),
1454  d2xyzdxi2_map[p](2), d2xyzdeta2_map[p](2), d2xyzdzeta2_map[p](2)),
1455 
1459 
1461  dxi (dxidx_map[p], dxidy_map[p], dxidz_map[p]),
1462  deta (detadx_map[p], detady_map[p], detadz_map[p]),
1463  dzeta(dzetadx_map[p], dzetady_map[p], dzetadz_map[p]);
1464 
1465  // In 3D, we have xx, xy, xz, yy, yz, and zz second derivatives
1466  const unsigned tmp[6] = {0,1,2,3,4,5};
1467  valid_indices.insert(tmp, tmp+6);
1468 
1469 #endif
1470 
1471  // For (s,t) in {(x,x), (x,y), (x,z), (y,y), (y,z), (z,z)}, compute the
1472  // vector of inverse map second derivatives [xi_{s t}, eta_{s t}, zeta_{s t}]
1473  unsigned ctr=0;
1474  for (unsigned s=0; s<3; ++s)
1475  for (unsigned t=s; t<3; ++t)
1476  {
1477  if (valid_indices.count(ctr))
1478  {
1480  v1(dxi(s)*dxi(t),
1481  deta(s)*deta(t),
1482  dzeta(s)*dzeta(t)),
1483 
1484  v2(dxi(s)*deta(t) + deta(s)*dxi(t),
1485  dxi(s)*dzeta(t) + dzeta(s)*dxi(t),
1486  deta(s)*dzeta(t) + dzeta(s)*deta(t));
1487 
1488  // Compute the inverse map second derivatives
1489  RealVectorValue v3 = -Jinv*(A*v1 + B*v2);
1490 
1491  // Store them in the appropriate locations in the class data structures
1492  d2xidxyz2_map[p][ctr] = v3(0);
1493 
1494  if (LIBMESH_DIM > 1)
1495  d2etadxyz2_map[p][ctr] = v3(1);
1496 
1497  if (LIBMESH_DIM > 2)
1498  d2zetadxyz2_map[p][ctr] = v3(2);
1499  }
1500 
1501  // Increment the counter
1502  ctr++;
1503  }
1504 #else
1505  // to avoid compiler warnings:
1506  libmesh_ignore(p);
1507 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
1508 }
1509 
1510 
1511 
1512 Point FEMap::inverse_map (const unsigned int dim,
1513  const Elem * elem,
1514  const Point & physical_point,
1515  const Real tolerance,
1516  const bool secure,
1517  const bool
1518  extra_checks
1519  )
1520 {
1521  libmesh_assert(elem);
1522  libmesh_assert_greater_equal (tolerance, 0.);
1523 
1524  libmesh_ignore(extra_checks);
1525 
1526 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1527 
1528  // TODO: possibly use the extra_checks parameter in InfFEMap::inverse_map() as well.
1529 
1530  if (elem->infinite())
1531  return InfFEMap::inverse_map(dim, elem, physical_point, tolerance,
1532  secure);
1533 #endif
1534 
1535  // Start logging the map inversion.
1536  LOG_SCOPE("inverse_map()", "FEMap");
1537 
1538  // How much did the point on the reference
1539  // element change by in this Newton step?
1540  Real inverse_map_error = 0.;
1541 
1542  // The point on the reference element. This is
1543  // the "initial guess" for Newton's method. The
1544  // centroid seems like a good idea, but computing
1545  // it is a little more intensive than, say taking
1546  // the zero point.
1547  //
1548  // Convergence should be insensitive of this choice
1549  // for "good" elements.
1550  Point p; // the zero point. No computation required
1551 
1552  // The number of iterations in the map inversion process.
1553  unsigned int cnt = 0;
1554 
1555  // The number of iterations after which we give up and declare
1556  // divergence
1557  const unsigned int max_cnt = 10;
1558 
1559  // The distance (in master element space) beyond which we give up
1560  // and declare divergence. This is no longer used...
1561  // Real max_step_length = 4.;
1562 
1563 
1564 
1565  // Newton iteration loop.
1566  do
1567  {
1568  // Where our current iterate \p p maps to.
1569  const Point physical_guess = map(dim, elem, p);
1570 
1571  // How far our current iterate is from the actual point.
1572  const Point delta = physical_point - physical_guess;
1573 
1574  // Increment in current iterate \p p, will be computed.
1575  Point dp;
1576 
1577 
1578  // The form of the map and how we invert it depends
1579  // on the dimension that we are in.
1580  switch (dim)
1581  {
1582  // ------------------------------------------------------------------
1583  // 0D map inversion is trivial
1584  case 0:
1585  {
1586  break;
1587  }
1588 
1589  // ------------------------------------------------------------------
1590  // 1D map inversion
1591  //
1592  // Here we find the point on a 1D reference element that maps to
1593  // the point \p physical_point in the domain. This is a bit tricky
1594  // since we do not want to assume that the point \p physical_point
1595  // is also in a 1D domain. In particular, this method might get
1596  // called on the edge of a 3D element, in which case
1597  // \p physical_point actually lives in 3D.
1598  case 1:
1599  {
1600  const Point dxi = map_deriv (dim, elem, 0, p);
1601 
1602  // Newton's method in this case looks like
1603  //
1604  // {X} - {X_n} = [J]*dp
1605  //
1606  // Where {X}, {X_n} are 3x1 vectors, [J] is a 3x1 matrix
1607  // d(x,y,z)/dxi, and we seek dp, a scalar. Since the above
1608  // system is either overdetermined or rank-deficient, we will
1609  // solve the normal equations for this system
1610  //
1611  // [J]^T ({X} - {X_n}) = [J]^T [J] {dp}
1612  //
1613  // which involves the trivial inversion of the scalar
1614  // G = [J]^T [J]
1615  const Real G = dxi*dxi;
1616 
1617  if (secure && G <= 0)
1618  libmesh_degenerate_mapping_msg
1619  ("inverse_map found a singular Jacobian " <<
1620  " at master point " << p << " in element " <<
1621  elem->id());
1622 
1623  const Real Ginv = 1./G;
1624 
1625  const Real dxidelta = dxi*delta;
1626 
1627  dp(0) = Ginv*dxidelta;
1628 
1629  // No master elements have radius > 4, but sometimes we
1630  // can take a step that big while still converging
1631  // if (secure)
1632  // libmesh_assert_less (dp.size(), max_step_length);
1633 
1634  break;
1635  }
1636 
1637 
1638 
1639  // ------------------------------------------------------------------
1640  // 2D map inversion
1641  //
1642  // Here we find the point on a 2D reference element that maps to
1643  // the point \p physical_point in the domain. This is a bit tricky
1644  // since we do not want to assume that the point \p physical_point
1645  // is also in a 2D domain. In particular, this method might get
1646  // called on the face of a 3D element, in which case
1647  // \p physical_point actually lives in 3D.
1648  case 2:
1649  {
1650  const Point dxi = map_deriv (dim, elem, 0, p);
1651  const Point deta = map_deriv (dim, elem, 1, p);
1652 
1653  // Newton's method in this case looks like
1654  //
1655  // {X} - {X_n} = [J]*{dp}
1656  //
1657  // Where {X}, {X_n} are 3x1 vectors, [J] is a 3x2 matrix
1658  // d(x,y,z)/d(xi,eta), and we seek {dp}, a 2x1 vector. Since
1659  // the above system is either over-determined or rank-deficient,
1660  // we will solve the normal equations for this system
1661  //
1662  // [J]^T ({X} - {X_n}) = [J]^T [J] {dp}
1663  //
1664  // which involves the inversion of the 2x2 matrix
1665  // [G] = [J]^T [J]
1666  const Real
1667  G11 = dxi*dxi, G12 = dxi*deta,
1668  G21 = dxi*deta, G22 = deta*deta;
1669 
1670 
1671  const Real det = (G11*G22 - G12*G21);
1672 
1673  if (secure && det == 0)
1674  libmesh_degenerate_mapping_msg
1675  ("inverse_map found a singular Jacobian " <<
1676  " at master point " << p << " in element " <<
1677  elem->id());
1678 
1679  const Real inv_det = 1./det;
1680 
1681  const Real
1682  Ginv11 = G22*inv_det,
1683  Ginv12 = -G12*inv_det,
1684 
1685  Ginv21 = -G21*inv_det,
1686  Ginv22 = G11*inv_det;
1687 
1688 
1689  const Real dxidelta = dxi*delta;
1690  const Real detadelta = deta*delta;
1691 
1692  dp(0) = (Ginv11*dxidelta + Ginv12*detadelta);
1693  dp(1) = (Ginv21*dxidelta + Ginv22*detadelta);
1694 
1695  // No master elements have radius > 4, but sometimes we
1696  // can take a step that big while still converging
1697  // if (secure)
1698  // libmesh_assert_less (dp.size(), max_step_length);
1699 
1700  break;
1701  }
1702 
1703 
1704 
1705  // ------------------------------------------------------------------
1706  // 3D map inversion
1707  //
1708  // Here we find the point in a 3D reference element that maps to
1709  // the point \p physical_point in a 3D domain. Nothing special
1710  // has to happen here, since (unless the map is singular because
1711  // you have a BAD element) the map will be invertible and we can
1712  // apply Newton's method directly.
1713  case 3:
1714  {
1715  const Point dxi = map_deriv (dim, elem, 0, p);
1716  const Point deta = map_deriv (dim, elem, 1, p);
1717  const Point dzeta = map_deriv (dim, elem, 2, p);
1718 
1719  // Newton's method in this case looks like
1720  //
1721  // {X} = {X_n} + [J]*{dp}
1722  //
1723  // Where {X}, {X_n} are 3x1 vectors, [J] is a 3x3 matrix
1724  // d(x,y,z)/d(xi,eta,zeta), and we seek {dp}, a 3x1 vector.
1725  // Since the above system is nonsingular for invertible maps
1726  // we will solve
1727  //
1728  // {dp} = [J]^-1 ({X} - {X_n})
1729  //
1730  // which involves the inversion of the 3x3 matrix [J]
1731  libmesh_try
1732  {
1733  RealTensorValue(dxi(0), deta(0), dzeta(0),
1734  dxi(1), deta(1), dzeta(1),
1735  dxi(2), deta(2), dzeta(2)).solve(delta, dp);
1736  }
1737  libmesh_catch (ConvergenceFailure &)
1738  {
1739  // If we encountered a singular Jacobian, but are at
1740  // a singular node, return said singular node.
1741  const unsigned int local_singular_node =
1742  elem->local_singular_node(physical_point, tolerance);
1743  if (local_singular_node != invalid_uint)
1744  {
1745  libmesh_assert_less(local_singular_node, elem->n_nodes());
1746  return elem->master_point(local_singular_node);
1747  }
1748 
1749  // We encountered a singular Jacobian. The value of
1750  // dp is zero, since it was never changed during the
1751  // call to RealTensorValue::solve(). We don't want to
1752  // continue iterating until max_cnt since there is no
1753  // update to the Newton iterate, and we don't want to
1754  // print the inverse_map_error value since it will
1755  // confusingly be 0. Therefore, in the secure case we
1756  // need to throw an error message while in the !secure
1757  // case we can just return a far away point.
1758  if (secure)
1759  {
1760  libmesh_degenerate_mapping_msg(
1761  "inverse_map found a singular Jacobian" <<
1762  " at master point " << p << " in element " <<
1763  elem->id());
1764  }
1765  else
1766  {
1767  for (unsigned int i=0; i != dim; ++i)
1768  p(i) = 1e6;
1769  return p;
1770  }
1771  }
1772 
1773  // No master elements have radius > 4, but sometimes we
1774  // can take a step that big while still converging
1775  // if (secure)
1776  // libmesh_assert_less (dp.size(), max_step_length);
1777 
1778  break;
1779  }
1780 
1781 
1782  // Some other dimension?
1783  default:
1784  libmesh_error_msg("Invalid dim = " << dim);
1785  } // end switch(Dim), dp now computed
1786 
1787 
1788 
1789  // ||P_n+1 - P_n||
1790  inverse_map_error = dp.norm();
1791 
1792  // P_n+1 = P_n + dp
1793  p.add (dp);
1794 
1795  // Increment the iteration count.
1796  cnt++;
1797 
1798  // Watch for divergence of Newton's
1799  // method. Here's how it goes:
1800  // (1) For good elements, we expect convergence in 10
1801  // iterations, with no too-large steps.
1802  // - If called with (secure == true) and we have not yet converged
1803  // print out a warning message.
1804  // - If called with (secure == true) and we have not converged in
1805  // 20 iterations abort
1806  // (2) This method may be called in cases when the target point is not
1807  // inside the element and we have no business expecting convergence.
1808  // For these cases if we have not converged in 10 iterations forget
1809  // about it.
1810  if (cnt > max_cnt)
1811  {
1812  // Warn about divergence when secure is true - this
1813  // shouldn't happen
1814  if (secure)
1815  {
1816  // Print every time in devel/dbg modes
1817 #ifndef NDEBUG
1818  libmesh_here();
1819  libMesh::err << "WARNING: Newton scheme has not converged in "
1820  << cnt << " iterations:" << std::endl
1821  << " physical_point="
1822  << physical_point
1823  << " physical_guess="
1824  << physical_guess
1825  << " dp="
1826  << dp
1827  << " p="
1828  << p
1829  << " error=" << inverse_map_error
1830  << " in element " << elem->id()
1831  << std::endl;
1832 
1833  elem->print_info(libMesh::err);
1834 #else
1835  // In optimized mode, just print once that an inverse_map() call
1836  // had trouble converging its Newton iteration.
1837  libmesh_do_once(libMesh::err << "WARNING: At least one element took more than "
1838  << max_cnt
1839  << " iterations to converge in inverse_map()...\n"
1840  << "Rerun in devel/dbg mode for more details."
1841  << std::endl;);
1842 
1843 #endif // NDEBUG
1844 
1845  if (cnt > 2*max_cnt)
1846  {
1847  // Whether or not this is a degenerate map in the
1848  // "Jacobian becomes singular or negative" sense,
1849  // it's at least degenerate in the "straightforward
1850  // Newton is failing to invert it" sense.
1851  libmesh_degenerate_mapping_msg(
1852  "inverse_map Newton FAILED to converge in " <<
1853  cnt << " iterations in element " << elem->id() <<
1854  " for physical point = " << physical_point <<
1855  std::endl << elem->get_info());
1856  }
1857  }
1858  // Return a far off point when secure is false - this
1859  // should only happen when we're trying to map a point
1860  // that's outside the element
1861  else
1862  {
1863  for (unsigned int i=0; i != dim; ++i)
1864  p(i) = 1e6;
1865 
1866  return p;
1867  }
1868  }
1869  }
1870  while (inverse_map_error > tolerance);
1871 
1872 
1873 
1874  // If we are in debug mode and the user requested it, do two extra sanity checks.
1875 #ifdef DEBUG
1876 
1877  if (extra_checks)
1878  {
1879  // Make sure the point \p p on the reference element actually
1880  // does map to the point \p physical_point within a tolerance.
1881 
1882  const Point check = map (dim, elem, p);
1883  const Point diff = physical_point - check;
1884 
1885  if (diff.norm() > tolerance)
1886  {
1887  libmesh_here();
1888  libMesh::err << "WARNING: diff is "
1889  << diff.norm()
1890  << std::endl
1891  << " point="
1892  << physical_point;
1893  libMesh::err << " local=" << check;
1894  libMesh::err << " lref= " << p;
1895 
1896  elem->print_info(libMesh::err);
1897  }
1898 
1899  // Make sure the point \p p on the reference element actually
1900  // is
1901 
1902  if (!elem->on_reference_element(p, 2*tolerance))
1903  {
1904  libmesh_here();
1905  libMesh::err << "WARNING: inverse_map of physical point "
1906  << physical_point
1907  << " is not on element." << '\n';
1908  elem->print_info(libMesh::err);
1909  }
1910  }
1911 
1912 #endif
1913 
1914  return p;
1915 }
1916 
1917 
1918 
1919 void FEMap::inverse_map (const unsigned int dim,
1920  const Elem * elem,
1921  const std::vector<Point> & physical_points,
1922  std::vector<Point> & reference_points,
1923  const Real tolerance,
1924  const bool secure,
1925  const bool extra_checks)
1926 {
1927 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1928  if (elem->infinite())
1929  {
1930  // TODO: possibly use the extra_checks parameter in InfFEMap::inverse_map() as well.
1931  libmesh_ignore(extra_checks);
1932 
1933  return InfFEMap::inverse_map(dim, elem, physical_points, reference_points, tolerance, secure);
1934  }
1935 #endif
1936 
1937  // The number of points to find the
1938  // inverse map of
1939  const std::size_t n_points = physical_points.size();
1940 
1941  // Resize the vector to hold the points
1942  // on the reference element
1943  reference_points.resize(n_points);
1944 
1945  // Find the coordinates on the reference
1946  // element of each point in physical space
1947  for (std::size_t p=0; p<n_points; p++)
1948  reference_points[p] =
1949  inverse_map (dim, elem, physical_points[p], tolerance, secure, extra_checks);
1950 }
1951 
1952 
1953 
1954 Point FEMap::map (const unsigned int dim,
1955  const Elem * elem,
1956  const Point & reference_point)
1957 {
1958  libmesh_assert(elem);
1960 
1961 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1962  if (elem->infinite())
1963  return InfFEMap::map(dim, elem, reference_point);
1964 #endif
1965 
1966  Point p;
1967 
1968  const FEFamily mapping_family = FEMap::map_fe_type(*elem);
1969  const FEType fe_type (elem->default_order(), mapping_family);
1970 
1971  // Do not consider the Elem::p_level(), if any, when computing the
1972  // number of shape functions.
1973  const unsigned int n_sf = FEInterface::n_shape_functions(fe_type, /*extra_order=*/0, elem);
1974 
1975  FEInterface::shape_ptr shape_ptr =
1976  FEInterface::shape_function(fe_type, elem);
1977 
1978  // Lagrange basis functions are used for mapping
1979  for (unsigned int i=0; i<n_sf; i++)
1980  p.add_scaled (elem->point(i),
1981  shape_ptr(fe_type, elem, i, reference_point, false));
1982 
1983  return p;
1984 }
1985 
1986 
1987 
1988 Point FEMap::map_deriv (const unsigned int dim,
1989  const Elem * elem,
1990  const unsigned int j,
1991  const Point & reference_point)
1992 {
1993  libmesh_assert(elem);
1995 
1996  if (elem->infinite())
1997  libmesh_not_implemented();
1998 
1999  Point p;
2000 
2001  const FEFamily mapping_family = FEMap::map_fe_type(*elem);
2002  const FEType fe_type (elem->default_order(), mapping_family);
2003 
2004  // Do not consider the Elem::p_level(), if any, when computing the
2005  // number of shape functions.
2006  const unsigned int n_sf =
2007  FEInterface::n_shape_functions(fe_type, /*total_order=*/0, elem);
2008 
2009  FEInterface::shape_deriv_ptr shape_deriv_ptr =
2010  FEInterface::shape_deriv_function(fe_type, elem);
2011 
2012  // Lagrange basis functions are used for mapping
2013  for (unsigned int i=0; i<n_sf; i++)
2014  p.add_scaled (elem->point(i),
2015  shape_deriv_ptr(fe_type, elem, i, j, reference_point,
2016  /*add_p_level=*/false));
2017 
2018  return p;
2019 }
2020 
2021 
2022 
2023 // Explicit instantiation of FEMap member functions
2024 template LIBMESH_EXPORT void FEMap::init_reference_to_physical_map<0>( const std::vector<Point> &, const Elem *);
2025 template LIBMESH_EXPORT void FEMap::init_reference_to_physical_map<1>( const std::vector<Point> &, const Elem *);
2026 template LIBMESH_EXPORT void FEMap::init_reference_to_physical_map<2>( const std::vector<Point> &, const Elem *);
2027 template LIBMESH_EXPORT void FEMap::init_reference_to_physical_map<3>( const std::vector<Point> &, const Elem *);
2028 
2029 // subdivision elements are implemented only for 2D meshes & reimplement
2030 // the inverse_maps method separately
2032 
2033 } // namespace libMesh
Real(* shape_deriv_ptr)(const FEType fet, const Elem *elem, const unsigned int i, const unsigned int j, const Point &p, const bool add_p_level)
Typedef for pointer to a function that returns FE shape function derivative values.
Definition: fe_interface.h:648
class FEType hides (possibly multiple) FEFamily and approximation orders, thereby enabling specialize...
Definition: fe_type.h:196
OStreamProxy err
virtual void compute_affine_map(const unsigned int dim, const std::vector< Real > &qw, const Elem *elem)
Compute the jacobian and some other additional data fields.
Definition: fe_map.C:1167
FEFamily family
The type of finite element.
Definition: fe_type.h:228
Real dzdeta_map(const unsigned int p) const
Used in FEMap::compute_map(), which should be be usable in derived classes, and therefore protected...
Definition: fe_map.h:711
void add_scaled(const TypeVector< T2 > &, const T &)
Add a scaled value to this vector without creating a temporary.
Definition: type_vector.h:629
void print_info(std::ostream &os=libMesh::out) const
Prints relevant information about the element.
Definition: elem.C:2948
static shape_ptr shape_function(const unsigned int dim, const FEType &fe_t, const ElemType t)
auto norm() const
Definition: type_vector.h:908
std::vector< std::vector< Real > > dphidzeta_map
Map for the derivative, d(phi)/d(zeta).
Definition: fe_map.h:894
const unsigned int invalid_uint
A number which is used quite often to represent an invalid or uninitialized value for an unsigned int...
Definition: libmesh.h:303
void compute_inverse_map_second_derivs(unsigned p)
A helper function used by FEMap::compute_single_point_map() to compute second derivatives of the inve...
Definition: fe_map.C:1392
virtual void compute_map(const unsigned int dim, const std::vector< Real > &qw, const Elem *elem, bool calculate_d2phi)
Compute the jacobian and some other additional data fields.
Definition: fe_map.C:1323
std::string get_info() const
Prints relevant information about the element to a string.
Definition: elem.C:2956
static Point map(const unsigned int dim, const Elem *inf_elem, const Point &reference_point)
Definition: inf_fe_map.C:40
std::vector< std::vector< Real > > dphidxi_map
Map for the derivative, d(phi)/d(xi).
Definition: fe_map.h:884
std::vector< std::vector< Real > > d2etadxyz2_map
Second derivatives of "eta" reference coordinate wrt physical coordinates.
Definition: fe_map.h:867
bool calculate_dxyz
Should we calculate mapping gradients?
Definition: fe_map.h:1016
static std::unique_ptr< FEMap > build(FEType fe_type)
Definition: fe_map.C:75
unsigned int dim
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true, const bool extra_checks=true)
Definition: fe_map.C:1512
std::vector< RealGradient > d2xyzdzeta2_map
Vector of second partial derivatives in zeta: d^2(x)/d(zeta)^2.
Definition: fe_map.h:796
std::vector< Real > dzetady_map
Map for partial derivatives: d(zeta)/d(y).
Definition: fe_map.h:848
std::vector< std::vector< Real > > d2xidxyz2_map
Second derivatives of "xi" reference coordinate wrt physical coordinates.
Definition: fe_map.h:861
virtual bool has_affine_map() const
Definition: elem.h:1188
Real dxdeta_map(const unsigned int p) const
Used in FEMap::compute_map(), which should be be usable in derived classes, and therefore protected...
Definition: fe_map.h:695
Real dzdxi_map(const unsigned int p) const
Used in FEMap::compute_map(), which should be be usable in derived classes, and therefore protected...
Definition: fe_map.h:687
This is the base class from which all geometric element types are derived.
Definition: elem.h:94
std::vector< std::vector< Real > > d2phideta2_map
Map for the second derivative, d^2(phi)/d(eta)^2.
Definition: fe_map.h:916
virtual bool on_reference_element(const Point &p, const Real eps=TOLERANCE) const =0
std::vector< std::vector< Real > > d2phidxidzeta_map
Map for the second derivative, d^2(phi)/d(xi)d(zeta).
Definition: fe_map.h:911
std::vector< Real > dxidz_map
Map for partial derivatives: d(xi)/d(z).
Definition: fe_map.h:816
std::vector< std::vector< Real > > phi_map
Map for the shape function phi.
Definition: fe_map.h:879
The libMesh namespace provides an interface to certain functionality in the library.
static Point inverse_map(const unsigned int dim, const Elem *elem, const Point &p, const Real tolerance=TOLERANCE, const bool secure=true)
Definition: inf_fe_map.C:96
virtual bool is_linear() const
Definition: elem.h:1204
std::vector< std::vector< Real > > d2phidetadzeta_map
Map for the second derivative, d^2(phi)/d(eta)d(zeta).
Definition: fe_map.h:921
static Threads::spin_mutex _point_inv_err_mutex
A mutex for locking the error stream for failed point inversions.
Definition: fe_map.h:1049
void add(const TypeVector< T2 > &)
Add to this vector without creating a temporary.
Definition: type_vector.h:605
std::vector< RealGradient > d2xyzdxideta_map
Vector of mixed second partial derivatives in xi-eta: d^2(x)/d(xi)d(eta) d^2(y)/d(xi)d(eta) d^2(z)/d(...
Definition: fe_map.h:772
std::vector< RealGradient > dxyzdzeta_map
Vector of partial derivatives: d(x)/d(zeta), d(y)/d(zeta), d(z)/d(zeta)
Definition: fe_map.h:758
std::vector< Real > dzetadx_map
Map for partial derivatives: d(zeta)/d(x).
Definition: fe_map.h:842
Definition: assembly.h:38
std::vector< RealGradient > dxyzdxi_map
Vector of partial derivatives: d(x)/d(xi), d(y)/d(xi), d(z)/d(xi)
Definition: fe_map.h:746
void find_one_ring(const Tri3Subdivision *elem, std::vector< const Node *> &nodes)
Determines the 1-ring of element elem, and writes it to the nodes vector.
TensorValue< Real > RealTensorValue
Useful typedefs to allow transparent switching between Real and Complex data types.
void libmesh_ignore(const Args &...)
const dof_id_type n_nodes
Definition: tecplot_io.C:67
std::vector< RealGradient > d2xyzdeta2_map
Vector of second partial derivatives in eta: d^2(x)/d(eta)^2.
Definition: fe_map.h:778
ElemMappingType mapping_type() const
Definition: elem.h:3134
dof_id_type id() const
Definition: dof_object.h:819
virtual unsigned int n_nodes() const =0
static unsigned int n_shape_functions(const unsigned int dim, const FEType &fe_t, const ElemType t)
Definition: fe_interface.C:272
std::vector< RealGradient > d2xyzdxi2_map
Vector of second partial derivatives in xi: d^2(x)/d(xi)^2, d^2(y)/d(xi)^2, d^2(z)/d(xi)^2.
Definition: fe_map.h:766
std::vector< Real > dzetadz_map
Map for partial derivatives: d(zeta)/d(z).
Definition: fe_map.h:854
Real dzdzeta_map(const unsigned int p) const
Used in FEMap::compute_map(), which should be be usable in derived classes, and therefore protected...
Definition: fe_map.h:735
bool calculate_d2xyz
Should we calculate mapping hessians?
Definition: fe_map.h:1023
std::vector< std::vector< Real > > d2zetadxyz2_map
Second derivatives of "zeta" reference coordinate wrt physical coordinates.
Definition: fe_map.h:873
bool calculations_started
Have calculations with this object already been started? Then all get_* functions should already have...
Definition: fe_map.h:1006
std::vector< RealGradient > d2xyzdetadzeta_map
Vector of mixed second partial derivatives in eta-zeta: d^2(x)/d(eta)d(zeta) d^2(y)/d(eta)d(zeta) d^2...
Definition: fe_map.h:790
libmesh_assert(ctx)
std::vector< Real > dxidx_map
Map for partial derivatives: d(xi)/d(x).
Definition: fe_map.h:804
The Tri3Subdivision element is a three-noded subdivision surface shell element used in mechanics calc...
bool calculate_xyz
Should we calculate physical point locations?
Definition: fe_map.h:1011
Real dxdzeta_map(const unsigned int p) const
Used in FEMap::compute_map(), which should be be usable in derived classes, and therefore protected...
Definition: fe_map.h:719
std::vector< Real > dxidy_map
Map for partial derivatives: d(xi)/d(y).
Definition: fe_map.h:810
INSTANTIATE_SUBDIVISION_MAPS
Definition: fe_map.C:2031
Real dydzeta_map(const unsigned int p) const
Used in FEMap::compute_map(), which should be be usable in derived classes, and therefore protected...
Definition: fe_map.h:727
static shape_deriv_ptr shape_deriv_function(const unsigned int dim, const FEType &fe_t, const ElemType t)
std::vector< const Node * > _elem_nodes
Work vector for compute_affine_map()
Definition: fe_map.h:1044
void init_reference_to_physical_map(const std::vector< Point > &qp, const Elem *elem)
Definition: fe_map.C:109
std::vector< Real > JxW
Jacobian*Weight values at quadrature points.
Definition: fe_map.h:1000
std::vector< std::vector< Real > > d2phidxideta_map
Map for the second derivative, d^2(phi)/d(xi)d(eta).
Definition: fe_map.h:906
tbb::spin_mutex spin_mutex
Spin mutex.
std::vector< Point > xyz
The spatial locations of the quadrature points.
Definition: fe_map.h:740
Real(* shape_ptr)(const FEType fe_t, const Elem *elem, const unsigned int i, const Point &p, const bool add_p_level)
Typedef for pointer to a function that returns FE shape function values.
Definition: fe_interface.h:541
DIE A HORRIBLE DEATH HERE typedef LIBMESH_DEFAULT_SCALAR_TYPE Real
Real dydeta_map(const unsigned int p) const
Used in FEMap::compute_map(), which should be be usable in derived classes, and therefore protected...
Definition: fe_map.h:703
static shape_second_deriv_ptr shape_second_deriv_function(const unsigned int dim, const FEType &fe_t, const ElemType t)
virtual unsigned int local_singular_node(const Point &, const Real=TOLERANCE *TOLERANCE) const
Definition: elem.h:1837
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:2513
virtual void compute_null_map(const unsigned int dim, const std::vector< Real > &qw)
Assign a fake jacobian and some other additional data fields.
Definition: fe_map.C:1248
A class representing a solver&#39;s failure to converge, to be thrown by "libmesh_convergence_failure();"...
static Point map(const unsigned int dim, const Elem *elem, const Point &reference_point)
Definition: fe_map.C:1954
std::vector< Real > detady_map
Map for partial derivatives: d(eta)/d(y).
Definition: fe_map.h:829
virtual Point master_point(const unsigned int i) const =0
void print_xyz(std::ostream &os) const
Prints the spatial location of each quadrature point (on the physical element).
Definition: fe_map.C:1384
std::vector< RealGradient > dxyzdeta_map
Vector of partial derivatives: d(x)/d(eta), d(y)/d(eta), d(z)/d(eta)
Definition: fe_map.h:752
void resize_quadrature_map_vectors(const unsigned int dim, unsigned int n_qp)
A utility function for use by compute_*_map.
Definition: fe_map.C:1086
static Point map_deriv(const unsigned int dim, const Elem *elem, const unsigned int j, const Point &reference_point)
Definition: fe_map.C:1988
IntRange< unsigned short > node_index_range() const
Definition: elem.h:2697
Real(* shape_second_deriv_ptr)(const FEType fet, const Elem *elem, const unsigned int i, const unsigned int j, const Point &p, const bool add_p_level)
Typedef for pointer to a function that returns FE shape function second derivative values...
Definition: fe_interface.h:753
FEMap(Real jtol=0)
Definition: fe_map.C:63
Real dxdxi_map(const unsigned int p) const
Used in FEMap::compute_map(), which should be be usable in derived classes, and therefore protected...
Definition: fe_map.h:671
void determine_calculations()
Determine which values are to be calculated.
Definition: fe_map.h:648
Real dydxi_map(const unsigned int p) const
Used in FEMap::compute_map(), which should be be usable in derived classes, and therefore protected...
Definition: fe_map.h:679
Defines a dense vector for use in Finite Element-type computations.
Definition: dof_map.h:74
virtual bool infinite() const =0
std::vector< Real > jac
Jacobian values at quadrature points.
Definition: fe_map.h:995
FEFamily
defines an enum for finite element families.
std::vector< Real > detadz_map
Map for partial derivatives: d(eta)/d(z).
Definition: fe_map.h:835
std::vector< std::vector< Real > > d2phidzeta2_map
Map for the second derivative, d^2(phi)/d(zeta)^2.
Definition: fe_map.h:926
void print_JxW(std::ostream &os) const
Prints the Jacobian times the weight for each quadrature point.
Definition: fe_map.C:1376
static void all_shape_derivs(const unsigned int dim, const FEType &fe_t, const Elem *elem, const std::vector< Point > &p, std::vector< std::vector< OutputType >> *comps[3], const bool add_p_level=true)
virtual Order default_order() const =0
std::vector< std::vector< Real > > d2phidxi2_map
Map for the second derivative, d^2(phi)/d(xi)^2.
Definition: fe_map.h:901
virtual ElemType type() const =0
A Point defines a location in LIBMESH_DIM dimensional Real space.
Definition: point.h:39
std::vector< Real > detadx_map
Map for partial derivatives: d(eta)/d(x).
Definition: fe_map.h:823
const Point & point(const unsigned int i) const
Definition: elem.h:2459
void compute_single_point_map(const unsigned int dim, const std::vector< Real > &qw, const Elem *elem, unsigned int p, const std::vector< const Node *> &elem_nodes, bool compute_second_derivatives)
Compute the jacobian and some other additional data fields at the single point with index p...
Definition: fe_map.C:448
std::vector< std::vector< Real > > dphideta_map
Map for the derivative, d(phi)/d(eta).
Definition: fe_map.h:889
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
void add_calculations()
Allows the user to prerequest additional calculations in between two calls to reinit();.
Definition: fe_map.C:89
static void all_shapes(const unsigned int dim, const FEType &fe_t, const Elem *elem, const std::vector< Point > &p, std::vector< std::vector< OutputType >> &phi, const bool add_p_level=true)
void vector_mult(DenseVector< T > &dest, const DenseVector< T > &arg) const
Performs the matrix-vector multiplication, dest := (*this) * arg.
This class defines a tensor in LIBMESH_DIM dimensional Real or Complex space.
static FEFamily map_fe_type(const Elem &elem)
Definition: fe_map.C:46
std::vector< RealGradient > d2xyzdxidzeta_map
Vector of second partial derivatives in xi-zeta: d^2(x)/d(xi)d(zeta), d^2(y)/d(xi)d(zeta), d^2(z)/d(xi)d(zeta)
Definition: fe_map.h:784
Real jacobian_tolerance
The Jacobian tolerance used for determining when the mapping fails.
Definition: fe_map.h:1032