libMesh
fe_map.C
Go to the documentation of this file.
1 // The libMesh Finite Element Library.
2 // Copyright (C) 2002-2025 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
3 
4 // This library is free software; you can redistribute it and/or
5 // modify it under the terms of the GNU Lesser General Public
6 // License as published by the Free Software Foundation; either
7 // version 2.1 of the License, or (at your option) any later version.
8 
9 // This library is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // Lesser General Public License for more details.
13 
14 // You should have received a copy of the GNU Lesser General Public
15 // License along with this library; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 
18 
19 
20 // Local includes
21 #include "libmesh/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  switch (dim)
468  {
469  //--------------------------------------------------------------------
470  // 0D
471  case 0:
472  {
473  libmesh_assert(elem_nodes[0]);
474  if (calculate_xyz)
475  xyz[p] = *elem_nodes[0];
476  if (calculate_dxyz)
477  {
478  jac[p] = 1.0;
479  JxW[p] = qw[p];
480  }
481  break;
482  }
483 
484  //--------------------------------------------------------------------
485  // 1D
486  case 1:
487  {
488  // Clear the entities that will be summed
489  if (calculate_xyz)
490  xyz[p].zero();
491  if (calculate_dxyz)
492  dxyzdxi_map[p].zero();
493 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
494  if (calculate_d2xyz)
495  {
496  d2xyzdxi2_map[p].zero();
497  // Inverse map second derivatives
498  d2xidxyz2_map[p].assign(6, 0.);
499  }
500 #endif
501 
502  // compute x, dx, d2x at the quadrature point
503  for (auto i : index_range(elem_nodes)) // sum over the nodes
504  {
505  // Reference to the point, helps eliminate
506  // excessive temporaries in the inner loop
507  libmesh_assert(elem_nodes[i]);
508  const Point & elem_point = *elem_nodes[i];
509 
510  if (calculate_xyz)
511  xyz[p].add_scaled (elem_point, phi_map[i][p] );
512  if (calculate_dxyz)
513  dxyzdxi_map[p].add_scaled (elem_point, dphidxi_map[i][p]);
514 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
515  if (calculate_d2xyz)
516  d2xyzdxi2_map[p].add_scaled(elem_point, d2phidxi2_map[i][p]);
517 #endif
518  }
519 
520  // Compute the jacobian
521  //
522  // 1D elements can live in 2D or 3D space.
523  // The transformation matrix from local->global
524  // coordinates is
525  //
526  // T = | dx/dxi |
527  // | dy/dxi |
528  // | dz/dxi |
529  //
530  // The generalized determinant of T (from the
531  // so-called "normal" eqns.) is
532  // jac = "det(T)" = sqrt(det(T'T))
533  //
534  // where T'= transpose of T, so
535  //
536  // jac = sqrt( (dx/dxi)^2 + (dy/dxi)^2 + (dz/dxi)^2 )
537 
538  if (calculate_dxyz)
539  {
540  jac[p] = dxyzdxi_map[p].norm();
541 
542  if (jac[p] <= jacobian_tolerance)
543  {
544  // Don't call print_info() recursively if we're already
545  // failing. print_info() calls Elem::volume() which may
546  // call FE::reinit() and trigger the same failure again.
547  static bool failing = false;
548  if (!failing)
549  {
550  failing = true;
551  elem->print_info(libMesh::err);
552  failing = false;
553  if (calculate_xyz)
554  {
555  libmesh_error_msg("ERROR: negative Jacobian " \
556  << jac[p] \
557  << " at point " \
558  << xyz[p] \
559  << " in element " \
560  << elem->id());
561  }
562  else
563  {
564  // In this case xyz[p] is not defined, so don't
565  // try to print it out.
566  libmesh_error_msg("ERROR: negative Jacobian " \
567  << jac[p] \
568  << " at point index " \
569  << p \
570  << " in element " \
571  << elem->id());
572  }
573  }
574  else
575  {
576  // We were already failing when we called this, so just
577  // stop the current computation and return with
578  // incomplete results.
579  return;
580  }
581  }
582 
583  // The inverse Jacobian entries also come from the
584  // generalized inverse of T (see also the 2D element
585  // living in 3D code).
586  const Real jacm2 = 1./jac[p]/jac[p];
587  dxidx_map[p] = jacm2*dxdxi_map(p);
588 #if LIBMESH_DIM > 1
589  dxidy_map[p] = jacm2*dydxi_map(p);
590 #endif
591 #if LIBMESH_DIM > 2
592  dxidz_map[p] = jacm2*dzdxi_map(p);
593 #endif
594 
595  JxW[p] = jac[p]*qw[p];
596  }
597 
598 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
599 
600  if (calculate_d2xyz)
601  {
602 #if LIBMESH_DIM == 1
603  // Compute inverse map second derivatives for 1D-element-living-in-1D case
605 #elif LIBMESH_DIM == 2
606  // Compute inverse map second derivatives for 1D-element-living-in-2D case
607  // See JWP notes for details
608 
609  // numer = x_xi*x_{xi xi} + y_xi*y_{xi xi}
610  Real numer =
611  dxyzdxi_map[p](0)*d2xyzdxi2_map[p](0) +
612  dxyzdxi_map[p](1)*d2xyzdxi2_map[p](1);
613 
614  // denom = (x_xi)^2 + (y_xi)^2 must be >= 0.0
615  Real denom =
616  dxyzdxi_map[p](0)*dxyzdxi_map[p](0) +
617  dxyzdxi_map[p](1)*dxyzdxi_map[p](1);
618 
619  if (denom <= 0.0)
620  {
621  // Don't call print_info() recursively if we're already
622  // failing. print_info() calls Elem::volume() which may
623  // call FE::reinit() and trigger the same failure again.
624  static bool failing = false;
625  if (!failing)
626  {
627  failing = true;
628  elem->print_info(libMesh::err);
629  failing = false;
630  libmesh_error_msg("Encountered invalid 1D element!");
631  }
632  else
633  {
634  // We were already failing when we called this, so just
635  // stop the current computation and return with
636  // incomplete results.
637  return;
638  }
639  }
640 
641  // xi_{x x}
642  d2xidxyz2_map[p][0] = -numer * dxidx_map[p]*dxidx_map[p] / denom;
643 
644  // xi_{x y}
645  d2xidxyz2_map[p][1] = -numer * dxidx_map[p]*dxidy_map[p] / denom;
646 
647  // xi_{y y}
648  d2xidxyz2_map[p][3] = -numer * dxidy_map[p]*dxidy_map[p] / denom;
649 
650 #elif LIBMESH_DIM == 3
651  // Compute inverse map second derivatives for 1D-element-living-in-3D case
652  // See JWP notes for details
653 
654  // numer = x_xi*x_{xi xi} + y_xi*y_{xi xi} + z_xi*z_{xi xi}
655  Real numer =
656  dxyzdxi_map[p](0)*d2xyzdxi2_map[p](0) +
657  dxyzdxi_map[p](1)*d2xyzdxi2_map[p](1) +
658  dxyzdxi_map[p](2)*d2xyzdxi2_map[p](2);
659 
660  // denom = (x_xi)^2 + (y_xi)^2 + (z_xi)^2 must be >= 0.0
661  Real denom =
662  dxyzdxi_map[p](0)*dxyzdxi_map[p](0) +
663  dxyzdxi_map[p](1)*dxyzdxi_map[p](1) +
664  dxyzdxi_map[p](2)*dxyzdxi_map[p](2);
665 
666  if (denom <= 0.0)
667  {
668  // Don't call print_info() recursively if we're already
669  // failing. print_info() calls Elem::volume() which may
670  // call FE::reinit() and trigger the same failure again.
671  static bool failing = false;
672  if (!failing)
673  {
674  failing = true;
675  elem->print_info(libMesh::err);
676  failing = false;
677  libmesh_error_msg("Encountered invalid 1D element!");
678  }
679  else
680  {
681  // We were already failing when we called this, so just
682  // stop the current computation and return with
683  // incomplete results.
684  return;
685  }
686  }
687 
688  // xi_{x x}
689  d2xidxyz2_map[p][0] = -numer * dxidx_map[p]*dxidx_map[p] / denom;
690 
691  // xi_{x y}
692  d2xidxyz2_map[p][1] = -numer * dxidx_map[p]*dxidy_map[p] / denom;
693 
694  // xi_{x z}
695  d2xidxyz2_map[p][2] = -numer * dxidx_map[p]*dxidz_map[p] / denom;
696 
697  // xi_{y y}
698  d2xidxyz2_map[p][3] = -numer * dxidy_map[p]*dxidy_map[p] / denom;
699 
700  // xi_{y z}
701  d2xidxyz2_map[p][4] = -numer * dxidy_map[p]*dxidz_map[p] / denom;
702 
703  // xi_{z z}
704  d2xidxyz2_map[p][5] = -numer * dxidz_map[p]*dxidz_map[p] / denom;
705 #endif //LIBMESH_DIM == 3
706  } // calculate_d2xyz
707 
708 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
709 
710  // done computing the map
711  break;
712  }
713 
714 
715  //--------------------------------------------------------------------
716  // 2D
717  case 2:
718  {
719  //------------------------------------------------------------------
720  // Compute the (x,y) values at the quadrature points,
721  // the Jacobian at the quadrature points
722 
723  if (calculate_xyz)
724  xyz[p].zero();
725 
726  if (calculate_dxyz)
727  {
728  dxyzdxi_map[p].zero();
729  dxyzdeta_map[p].zero();
730  }
731 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
732  if (calculate_d2xyz)
733  {
734  d2xyzdxi2_map[p].zero();
735  d2xyzdxideta_map[p].zero();
736  d2xyzdeta2_map[p].zero();
737  // Inverse map second derivatives
738  d2xidxyz2_map[p].assign(6, 0.);
739  d2etadxyz2_map[p].assign(6, 0.);
740  }
741 #endif
742 
743 
744  // compute (x,y) at the quadrature points, derivatives once
745  for (auto i : index_range(elem_nodes)) // sum over the nodes
746  {
747  // Reference to the point, helps eliminate
748  // excessive temporaries in the inner loop
749  libmesh_assert(elem_nodes[i]);
750  const Point & elem_point = *elem_nodes[i];
751 
752  if (calculate_xyz)
753  xyz[p].add_scaled (elem_point, phi_map[i][p] );
754 
755  if (calculate_dxyz)
756  {
757  dxyzdxi_map[p].add_scaled (elem_point, dphidxi_map[i][p] );
758  dxyzdeta_map[p].add_scaled (elem_point, dphideta_map[i][p]);
759  }
760 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
761  if (calculate_d2xyz)
762  {
763  d2xyzdxi2_map[p].add_scaled (elem_point, d2phidxi2_map[i][p]);
764  d2xyzdxideta_map[p].add_scaled (elem_point, d2phidxideta_map[i][p]);
765  d2xyzdeta2_map[p].add_scaled (elem_point, d2phideta2_map[i][p]);
766  }
767 #endif
768  }
769 
770  if (calculate_dxyz)
771  {
772  // compute the jacobian once
773  const Real dx_dxi = dxdxi_map(p),
774  dx_deta = dxdeta_map(p),
775  dy_dxi = dydxi_map(p),
776  dy_deta = dydeta_map(p);
777 
778 #if LIBMESH_DIM == 2
779  // Compute the Jacobian. This assumes the 2D face
780  // lives in 2D space
781  //
782  // Symbolically, the matrix determinant is
783  //
784  // | dx/dxi dx/deta |
785  // jac = | dy/dxi dy/deta |
786  //
787  // jac = dx/dxi*dy/deta - dx/deta*dy/dxi
788  jac[p] = (dx_dxi*dy_deta - dx_deta*dy_dxi);
789 
790  if (jac[p] <= jacobian_tolerance)
791  {
792  // Don't call print_info() recursively if we're already
793  // failing. print_info() calls Elem::volume() which may
794  // call FE::reinit() and trigger the same failure again.
795  static bool failing = false;
796  if (!failing)
797  {
798  failing = true;
799  elem->print_info(libMesh::err);
800  failing = false;
801  if (calculate_xyz)
802  {
803  libmesh_error_msg("ERROR: negative Jacobian " \
804  << jac[p] \
805  << " at point " \
806  << xyz[p] \
807  << " in element " \
808  << elem->id());
809  }
810  else
811  {
812  // In this case xyz[p] is not defined, so don't
813  // try to print it out.
814  libmesh_error_msg("ERROR: negative Jacobian " \
815  << jac[p] \
816  << " at point index " \
817  << p \
818  << " in element " \
819  << elem->id());
820  }
821  }
822  else
823  {
824  // We were already failing when we called this, so just
825  // stop the current computation and return with
826  // incomplete results.
827  return;
828  }
829  }
830 
831  JxW[p] = jac[p]*qw[p];
832 
833  // Compute the shape function derivatives wrt x,y at the
834  // quadrature points
835  const Real inv_jac = 1./jac[p];
836 
837  dxidx_map[p] = dy_deta*inv_jac; //dxi/dx = (1/J)*dy/deta
838  dxidy_map[p] = -dx_deta*inv_jac; //dxi/dy = -(1/J)*dx/deta
839  detadx_map[p] = -dy_dxi* inv_jac; //deta/dx = -(1/J)*dy/dxi
840  detady_map[p] = dx_dxi* inv_jac; //deta/dy = (1/J)*dx/dxi
841 
842  dxidz_map[p] = detadz_map[p] = 0.;
843 
844 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
845  if (compute_second_derivatives)
847 #endif
848 #else // LIBMESH_DIM == 3
849 
850  const Real dz_dxi = dzdxi_map(p),
851  dz_deta = dzdeta_map(p);
852 
853  // Compute the Jacobian. This assumes a 2D face in
854  // 3D space.
855  //
856  // The transformation matrix T from local to global
857  // coordinates is
858  //
859  // | dx/dxi dx/deta |
860  // T = | dy/dxi dy/deta |
861  // | dz/dxi dz/deta |
862  // note det(T' T) = det(T')det(T) = det(T)det(T)
863  // so det(T) = std::sqrt(det(T' T))
864  //
865  //----------------------------------------------
866  // Notes:
867  //
868  // dX = R dXi -> R'dX = R'R dXi
869  // (R^-1)dX = dXi [(R'R)^-1 R']dX = dXi
870  //
871  // so R^-1 = (R'R)^-1 R'
872  //
873  // and R^-1 R = (R'R)^-1 R'R = I.
874  //
875  const Real g11 = (dx_dxi*dx_dxi +
876  dy_dxi*dy_dxi +
877  dz_dxi*dz_dxi);
878 
879  const Real g12 = (dx_dxi*dx_deta +
880  dy_dxi*dy_deta +
881  dz_dxi*dz_deta);
882 
883  const Real g21 = g12;
884 
885  const Real g22 = (dx_deta*dx_deta +
886  dy_deta*dy_deta +
887  dz_deta*dz_deta);
888 
889  const Real det = (g11*g22 - g12*g21);
890 
891  if (det <= jacobian_tolerance)
892  {
893  // Don't call print_info() recursively if we're already
894  // failing. print_info() calls Elem::volume() which may
895  // call FE::reinit() and trigger the same failure again.
896  thread_local bool failing = false;
897  if (!failing)
898  {
899  failing = true;
900  Threads::spin_mutex::scoped_lock lock(_point_inv_err_mutex);
901  elem->print_info(libMesh::err);
902  failing = false;
903  if (calculate_xyz)
904  {
905  libmesh_error_msg("ERROR: negative Jacobian " \
906  << det \
907  << " at point " \
908  << xyz[p] \
909  << " in element " \
910  << elem->id());
911  }
912  else
913  {
914  // In this case xyz[p] is not defined, so don't
915  // try to print it out.
916  libmesh_error_msg("ERROR: negative Jacobian " \
917  << det \
918  << " at point index " \
919  << p \
920  << " in element " \
921  << elem->id());
922  }
923  }
924  else
925  {
926  // We were already failing when we called this, so just
927  // stop the current computation and return with
928  // incomplete results.
929  return;
930  }
931  }
932 
933  const Real inv_det = 1./det;
934  jac[p] = std::sqrt(det);
935 
936  JxW[p] = jac[p]*qw[p];
937 
938  const Real g11inv = g22*inv_det;
939  const Real g12inv = -g12*inv_det;
940  const Real g21inv = -g21*inv_det;
941  const Real g22inv = g11*inv_det;
942 
943  dxidx_map[p] = g11inv*dx_dxi + g12inv*dx_deta;
944  dxidy_map[p] = g11inv*dy_dxi + g12inv*dy_deta;
945  dxidz_map[p] = g11inv*dz_dxi + g12inv*dz_deta;
946 
947  detadx_map[p] = g21inv*dx_dxi + g22inv*dx_deta;
948  detady_map[p] = g21inv*dy_dxi + g22inv*dy_deta;
949  detadz_map[p] = g21inv*dz_dxi + g22inv*dz_deta;
950 
951 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
952 
953  if (calculate_d2xyz)
954  {
955  // Compute inverse map second derivative values for
956  // 2D-element-living-in-3D case. We pursue a least-squares
957  // solution approach for this "non-square" case, see JWP notes
958  // for details.
959 
960  // A = [ x_{xi xi} x_{eta eta} ]
961  // [ y_{xi xi} y_{eta eta} ]
962  // [ z_{xi xi} z_{eta eta} ]
963  DenseMatrix<Real> A(3,2);
964  A(0,0) = d2xyzdxi2_map[p](0); A(0,1) = d2xyzdeta2_map[p](0);
965  A(1,0) = d2xyzdxi2_map[p](1); A(1,1) = d2xyzdeta2_map[p](1);
966  A(2,0) = d2xyzdxi2_map[p](2); A(2,1) = d2xyzdeta2_map[p](2);
967 
968  // J^T, the transpose of the Jacobian matrix
969  DenseMatrix<Real> JT(2,3);
970  JT(0,0) = dx_dxi; JT(0,1) = dy_dxi; JT(0,2) = dz_dxi;
971  JT(1,0) = dx_deta; JT(1,1) = dy_deta; JT(1,2) = dz_deta;
972 
973  // (J^T J)^(-1), this has already been computed for us above...
974  DenseMatrix<Real> JTJinv(2,2);
975  JTJinv(0,0) = g11inv; JTJinv(0,1) = g12inv;
976  JTJinv(1,0) = g21inv; JTJinv(1,1) = g22inv;
977 
978  // Some helper variables
980  dxi (dxidx_map[p], dxidy_map[p], dxidz_map[p]),
981  deta (detadx_map[p], detady_map[p], detadz_map[p]);
982 
983  // To be filled in below
984  DenseVector<Real> tmp1(2);
985  DenseVector<Real> tmp2(3);
986  DenseVector<Real> tmp3(2);
987 
988  // For (s,t) in {(x,x), (x,y), (x,z), (y,y), (y,z), (z,z)}, compute the
989  // vector of inverse map second derivatives [xi_{s t}, eta_{s t}]
990  unsigned ctr=0;
991  for (unsigned s=0; s<3; ++s)
992  for (unsigned t=s; t<3; ++t)
993  {
994  // Construct tmp1 = [xi_s*xi_t, eta_s*eta_t]
995  tmp1(0) = dxi(s)*dxi(t);
996  tmp1(1) = deta(s)*deta(t);
997 
998  // Compute tmp2 = A * tmp1
999  A.vector_mult(tmp2, tmp1);
1000 
1001  // Compute scalar value "alpha"
1002  Real alpha = dxi(s)*deta(t) + deta(s)*dxi(t);
1003 
1004  // Compute tmp2 <- tmp2 + alpha * x_{xi eta}
1005  for (unsigned i=0; i<3; ++i)
1006  tmp2(i) += alpha*d2xyzdxideta_map[p](i);
1007 
1008  // Compute tmp3 = J^T * tmp2
1009  JT.vector_mult(tmp3, tmp2);
1010 
1011  // Compute tmp1 = (J^T J)^(-1) * tmp3. tmp1 is available for us to reuse.
1012  JTJinv.vector_mult(tmp1, tmp3);
1013 
1014  // Fill in appropriate entries, don't forget to multiply by -1!
1015  d2xidxyz2_map[p][ctr] = -tmp1(0);
1016  d2etadxyz2_map[p][ctr] = -tmp1(1);
1017 
1018  // Increment the counter
1019  ctr++;
1020  }
1021  }
1022 
1023 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
1024 
1025 #endif // LIBMESH_DIM == 3
1026  }
1027  // done computing the map
1028  break;
1029  }
1030 
1031 
1032 
1033  //--------------------------------------------------------------------
1034  // 3D
1035  case 3:
1036  {
1037  //------------------------------------------------------------------
1038  // Compute the (x,y,z) values at the quadrature points,
1039  // the Jacobian at the quadrature point
1040 
1041  // Clear the entities that will be summed
1042  if (calculate_xyz)
1043  xyz[p].zero ();
1044  if (calculate_dxyz)
1045  {
1046  dxyzdxi_map[p].zero ();
1047  dxyzdeta_map[p].zero ();
1048  dxyzdzeta_map[p].zero ();
1049  }
1050 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1051  if (calculate_d2xyz)
1052  {
1053  d2xyzdxi2_map[p].zero();
1054  d2xyzdxideta_map[p].zero();
1055  d2xyzdxidzeta_map[p].zero();
1056  d2xyzdeta2_map[p].zero();
1057  d2xyzdetadzeta_map[p].zero();
1058  d2xyzdzeta2_map[p].zero();
1059  // Inverse map second derivatives
1060  d2xidxyz2_map[p].assign(6, 0.);
1061  d2etadxyz2_map[p].assign(6, 0.);
1062  d2zetadxyz2_map[p].assign(6, 0.);
1063  }
1064 #endif
1065 
1066 
1067  // compute (x,y,z) at the quadrature points,
1068  // dxdxi, dydxi, dzdxi,
1069  // dxdeta, dydeta, dzdeta,
1070  // dxdzeta, dydzeta, dzdzeta all once
1071  for (auto i : index_range(elem_nodes)) // sum over the nodes
1072  {
1073  // Reference to the point, helps eliminate
1074  // excessive temporaries in the inner loop
1075  libmesh_assert(elem_nodes[i]);
1076  const Point & elem_point = *elem_nodes[i];
1077 
1078  if (calculate_xyz)
1079  xyz[p].add_scaled (elem_point, phi_map[i][p] );
1080  if (calculate_dxyz)
1081  {
1082  dxyzdxi_map[p].add_scaled (elem_point, dphidxi_map[i][p] );
1083  dxyzdeta_map[p].add_scaled (elem_point, dphideta_map[i][p] );
1084  dxyzdzeta_map[p].add_scaled (elem_point, dphidzeta_map[i][p]);
1085  }
1086 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1087  if (calculate_d2xyz)
1088  {
1089  d2xyzdxi2_map[p].add_scaled (elem_point,
1090  d2phidxi2_map[i][p]);
1091  d2xyzdxideta_map[p].add_scaled (elem_point,
1092  d2phidxideta_map[i][p]);
1093  d2xyzdxidzeta_map[p].add_scaled (elem_point,
1094  d2phidxidzeta_map[i][p]);
1095  d2xyzdeta2_map[p].add_scaled (elem_point,
1096  d2phideta2_map[i][p]);
1097  d2xyzdetadzeta_map[p].add_scaled (elem_point,
1098  d2phidetadzeta_map[i][p]);
1099  d2xyzdzeta2_map[p].add_scaled (elem_point,
1100  d2phidzeta2_map[i][p]);
1101  }
1102 #endif
1103  }
1104 
1105  if (calculate_dxyz)
1106  {
1107  // compute the jacobian
1108  const Real
1109  dx_dxi = dxdxi_map(p), dy_dxi = dydxi_map(p), dz_dxi = dzdxi_map(p),
1110  dx_deta = dxdeta_map(p), dy_deta = dydeta_map(p), dz_deta = dzdeta_map(p),
1111  dx_dzeta = dxdzeta_map(p), dy_dzeta = dydzeta_map(p), dz_dzeta = dzdzeta_map(p);
1112 
1113  // Symbolically, the matrix determinant is
1114  //
1115  // | dx/dxi dy/dxi dz/dxi |
1116  // jac = | dx/deta dy/deta dz/deta |
1117  // | dx/dzeta dy/dzeta dz/dzeta |
1118  //
1119  // jac = dx/dxi*(dy/deta*dz/dzeta - dz/deta*dy/dzeta) +
1120  // dy/dxi*(dz/deta*dx/dzeta - dx/deta*dz/dzeta) +
1121  // dz/dxi*(dx/deta*dy/dzeta - dy/deta*dx/dzeta)
1122 
1123  jac[p] = (dx_dxi*(dy_deta*dz_dzeta - dz_deta*dy_dzeta) +
1124  dy_dxi*(dz_deta*dx_dzeta - dx_deta*dz_dzeta) +
1125  dz_dxi*(dx_deta*dy_dzeta - dy_deta*dx_dzeta));
1126 
1127  if (jac[p] <= jacobian_tolerance)
1128  {
1129  // Don't call print_info() recursively if we're already
1130  // failing. print_info() calls Elem::volume() which may
1131  // call FE::reinit() and trigger the same failure again.
1132  static bool failing = false;
1133  if (!failing)
1134  {
1135  failing = true;
1136  elem->print_info(libMesh::err);
1137  failing = false;
1138  if (calculate_xyz)
1139  {
1140  libmesh_error_msg("ERROR: negative Jacobian " \
1141  << jac[p] \
1142  << " at point " \
1143  << xyz[p] \
1144  << " in element " \
1145  << elem->id());
1146  }
1147  else
1148  {
1149  // In this case xyz[p] is not defined, so don't
1150  // try to print it out.
1151  libmesh_error_msg("ERROR: negative Jacobian " \
1152  << jac[p] \
1153  << " at point index " \
1154  << p \
1155  << " in element " \
1156  << elem->id());
1157  }
1158  }
1159  else
1160  {
1161  // We were already failing when we called this, so just
1162  // stop the current computation and return with
1163  // incomplete results.
1164  return;
1165  }
1166  }
1167 
1168  JxW[p] = jac[p]*qw[p];
1169 
1170  // Compute the shape function derivatives wrt x,y at the
1171  // quadrature points
1172  const Real inv_jac = 1./jac[p];
1173 
1174  dxidx_map[p] = (dy_deta*dz_dzeta - dz_deta*dy_dzeta)*inv_jac;
1175  dxidy_map[p] = (dz_deta*dx_dzeta - dx_deta*dz_dzeta)*inv_jac;
1176  dxidz_map[p] = (dx_deta*dy_dzeta - dy_deta*dx_dzeta)*inv_jac;
1177 
1178  detadx_map[p] = (dz_dxi*dy_dzeta - dy_dxi*dz_dzeta )*inv_jac;
1179  detady_map[p] = (dx_dxi*dz_dzeta - dz_dxi*dx_dzeta )*inv_jac;
1180  detadz_map[p] = (dy_dxi*dx_dzeta - dx_dxi*dy_dzeta )*inv_jac;
1181 
1182  dzetadx_map[p] = (dy_dxi*dz_deta - dz_dxi*dy_deta )*inv_jac;
1183  dzetady_map[p] = (dz_dxi*dx_deta - dx_dxi*dz_deta )*inv_jac;
1184  dzetadz_map[p] = (dx_dxi*dy_deta - dy_dxi*dx_deta )*inv_jac;
1185  }
1186 
1187 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1188  if (compute_second_derivatives)
1190 #endif
1191  // done computing the map
1192  break;
1193  }
1194 
1195  default:
1196  libmesh_error_msg("Invalid dim = " << dim);
1197  }
1198 }
1199 
1200 
1201 
1202 void FEMap::resize_quadrature_map_vectors(const unsigned int dim, unsigned int n_qp)
1203 {
1204  // We're calculating now!
1205  this->determine_calculations();
1206 
1207  // Resize the vectors to hold data at the quadrature points
1208  if (calculate_xyz)
1209  xyz.resize(n_qp);
1210  if (calculate_dxyz)
1211  {
1212  dxyzdxi_map.resize(n_qp);
1213  dxidx_map.resize(n_qp);
1214  dxidy_map.resize(n_qp); // 1D element may live in 2D ...
1215  dxidz_map.resize(n_qp); // ... or 3D
1216  }
1217 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1218  if (calculate_d2xyz)
1219  {
1220  d2xyzdxi2_map.resize(n_qp);
1221 
1222  // Inverse map second derivatives
1223  d2xidxyz2_map.resize(n_qp);
1224  for (auto i : index_range(d2xidxyz2_map))
1225  d2xidxyz2_map[i].assign(6, 0.);
1226  }
1227 #endif
1228  if (dim > 1)
1229  {
1230  if (calculate_dxyz)
1231  {
1232  dxyzdeta_map.resize(n_qp);
1233  detadx_map.resize(n_qp);
1234  detady_map.resize(n_qp);
1235  detadz_map.resize(n_qp);
1236  }
1237 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1238  if (calculate_d2xyz)
1239  {
1240  d2xyzdxideta_map.resize(n_qp);
1241  d2xyzdeta2_map.resize(n_qp);
1242 
1243  // Inverse map second derivatives
1244  d2etadxyz2_map.resize(n_qp);
1245  for (auto i : index_range(d2etadxyz2_map))
1246  d2etadxyz2_map[i].assign(6, 0.);
1247  }
1248 #endif
1249  if (dim > 2)
1250  {
1251  if (calculate_dxyz)
1252  {
1253  dxyzdzeta_map.resize (n_qp);
1254  dzetadx_map.resize (n_qp);
1255  dzetady_map.resize (n_qp);
1256  dzetadz_map.resize (n_qp);
1257  }
1258 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1259  if (calculate_d2xyz)
1260  {
1261  d2xyzdxidzeta_map.resize(n_qp);
1262  d2xyzdetadzeta_map.resize(n_qp);
1263  d2xyzdzeta2_map.resize(n_qp);
1264 
1265  // Inverse map second derivatives
1266  d2zetadxyz2_map.resize(n_qp);
1267  for (auto i : index_range(d2zetadxyz2_map))
1268  d2zetadxyz2_map[i].assign(6, 0.);
1269  }
1270 #endif
1271  }
1272  }
1273 
1274  if (calculate_dxyz)
1275  {
1276  jac.resize(n_qp);
1277  JxW.resize(n_qp);
1278  }
1279 }
1280 
1281 
1282 
1283 void FEMap::compute_affine_map(const unsigned int dim,
1284  const std::vector<Real> & qw,
1285  const Elem * elem)
1286 {
1287  // Start logging the map computation.
1288  LOG_SCOPE("compute_affine_map()", "FEMap");
1289 
1290  libmesh_assert(elem);
1291 
1292  const unsigned int n_qp = cast_int<unsigned int>(qw.size());
1293 
1294  // Resize the vectors to hold data at the quadrature points
1295  this->resize_quadrature_map_vectors(dim, n_qp);
1296 
1297  // Determine the nodes contributing to element elem
1298  unsigned int n_nodes = elem->n_nodes();
1299  _elem_nodes.resize(elem->n_nodes());
1300  for (unsigned int i=0; i<n_nodes; i++)
1301  _elem_nodes[i] = elem->node_ptr(i);
1302 
1303  // Compute map at quadrature point 0
1304  this->compute_single_point_map(dim, qw, elem, 0, _elem_nodes, /*compute_second_derivatives=*/false);
1305 
1306  // Compute xyz at all other quadrature points
1307  if (calculate_xyz)
1308  for (unsigned int p=1; p<n_qp; p++)
1309  {
1310  xyz[p].zero();
1311  for (auto i : index_range(phi_map)) // sum over the nodes
1312  xyz[p].add_scaled (*_elem_nodes[i], phi_map[i][p]);
1313  }
1314 
1315  // Copy other map data from quadrature point 0
1316  if (calculate_dxyz)
1317  for (unsigned int p=1; p<n_qp; p++) // for each extra quadrature point
1318  {
1319  dxyzdxi_map[p] = dxyzdxi_map[0];
1320  dxidx_map[p] = dxidx_map[0];
1321  dxidy_map[p] = dxidy_map[0];
1322  dxidz_map[p] = dxidz_map[0];
1323 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1324  // The map should be affine, so second derivatives are zero
1325  if (calculate_d2xyz)
1326  d2xyzdxi2_map[p] = 0.;
1327 #endif
1328  if (dim > 1)
1329  {
1330  dxyzdeta_map[p] = dxyzdeta_map[0];
1331  detadx_map[p] = detadx_map[0];
1332  detady_map[p] = detady_map[0];
1333  detadz_map[p] = detadz_map[0];
1334 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1335  if (calculate_d2xyz)
1336  {
1337  d2xyzdxideta_map[p] = 0.;
1338  d2xyzdeta2_map[p] = 0.;
1339  }
1340 #endif
1341  if (dim > 2)
1342  {
1343  dxyzdzeta_map[p] = dxyzdzeta_map[0];
1344  dzetadx_map[p] = dzetadx_map[0];
1345  dzetady_map[p] = dzetady_map[0];
1346  dzetadz_map[p] = dzetadz_map[0];
1347 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1348  if (calculate_d2xyz)
1349  {
1350  d2xyzdxidzeta_map[p] = 0.;
1351  d2xyzdetadzeta_map[p] = 0.;
1352  d2xyzdzeta2_map[p] = 0.;
1353  }
1354 #endif
1355  }
1356  }
1357  jac[p] = jac[0];
1358  JxW[p] = JxW[0] / qw[0] * qw[p];
1359  }
1360 }
1361 
1362 
1363 
1364 void FEMap::compute_null_map(const unsigned int dim,
1365  const std::vector<Real> & qw)
1366 {
1367  // Start logging the map computation.
1368  LOG_SCOPE("compute_null_map()", "FEMap");
1369 
1370  const unsigned int n_qp = cast_int<unsigned int>(qw.size());
1371 
1372  // Resize the vectors to hold data at the quadrature points
1373  this->resize_quadrature_map_vectors(dim, n_qp);
1374 
1375  // Compute "fake" xyz
1376  for (unsigned int p=1; p<n_qp; p++)
1377  {
1378  if (calculate_xyz)
1379  xyz[p].zero();
1380 
1381  if (calculate_dxyz)
1382  {
1383  dxyzdxi_map[p] = 0;
1384  dxidx_map[p] = 0;
1385  dxidy_map[p] = 0;
1386  dxidz_map[p] = 0;
1387  }
1388 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1389  if (calculate_d2xyz)
1390  {
1391  d2xyzdxi2_map[p] = 0;
1392  }
1393 #endif
1394  if (dim > 1)
1395  {
1396  if (calculate_dxyz)
1397  {
1398  dxyzdeta_map[p] = 0;
1399  detadx_map[p] = 0;
1400  detady_map[p] = 0;
1401  detadz_map[p] = 0;
1402  }
1403 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1404  if (calculate_d2xyz)
1405  {
1406  d2xyzdxideta_map[p] = 0.;
1407  d2xyzdeta2_map[p] = 0.;
1408  }
1409 #endif
1410  if (dim > 2)
1411  {
1412  if (calculate_dxyz)
1413  {
1414  dxyzdzeta_map[p] = 0;
1415  dzetadx_map[p] = 0;
1416  dzetady_map[p] = 0;
1417  dzetadz_map[p] = 0;
1418  }
1419 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1420  if (calculate_d2xyz)
1421  {
1422  d2xyzdxidzeta_map[p] = 0;
1423  d2xyzdetadzeta_map[p] = 0;
1424  d2xyzdzeta2_map[p] = 0;
1425  }
1426 #endif
1427  }
1428  }
1429  if (calculate_dxyz)
1430  {
1431  jac[p] = 1;
1432  JxW[p] = qw[p];
1433  }
1434  }
1435 }
1436 
1437 
1438 
1439 void FEMap::compute_map(const unsigned int dim,
1440  const std::vector<Real> & qw,
1441  const Elem * elem,
1442  bool calculate_d2phi)
1443 {
1444  if (!elem)
1445  {
1446  compute_null_map(dim, qw);
1447  return;
1448  }
1449 
1450  if (elem->has_affine_map())
1451  {
1452  compute_affine_map(dim, qw, elem);
1453  return;
1454  }
1455 #ifndef LIBMESH_ENABLE_SECOND_DERIVATIVES
1456  libmesh_assert(!calculate_d2phi);
1457 #endif
1458 
1459  // Start logging the map computation.
1460  LOG_SCOPE("compute_map()", "FEMap");
1461 
1462  libmesh_assert(elem);
1463 
1464  const unsigned int n_qp = cast_int<unsigned int>(qw.size());
1465 
1466  // Resize the vectors to hold data at the quadrature points
1467  this->resize_quadrature_map_vectors(dim, n_qp);
1468 
1469  // Determine the nodes contributing to element elem
1470  if (elem->type() == TRI3SUBDIVISION)
1471  {
1472  // Subdivision surface FE require the 1-ring around elem
1473  libmesh_assert_equal_to (dim, 2);
1474  const Tri3Subdivision * sd_elem = static_cast<const Tri3Subdivision *>(elem);
1476  }
1477  else
1478  {
1479  // All other FE use only the nodes of elem itself
1480  _elem_nodes.resize(elem->n_nodes(), nullptr);
1481  for (auto i : elem->node_index_range())
1482  _elem_nodes[i] = elem->node_ptr(i);
1483  }
1484 
1485  // Compute map at all quadrature points
1486  for (unsigned int p=0; p!=n_qp; p++)
1487  this->compute_single_point_map(dim, qw, elem, p, _elem_nodes, calculate_d2phi);
1488 }
1489 
1490 
1491 
1492 void FEMap::print_JxW(std::ostream & os) const
1493 {
1494  for (auto i : index_range(JxW))
1495  os << " [" << i << "]: " << JxW[i] << std::endl;
1496 }
1497 
1498 
1499 
1500 void FEMap::print_xyz(std::ostream & os) const
1501 {
1502  for (auto i : index_range(xyz))
1503  os << " [" << i << "]: " << xyz[i];
1504 }
1505 
1506 
1507 
1509 {
1510 #ifdef LIBMESH_ENABLE_SECOND_DERIVATIVES
1511  // Only certain second derivatives are valid depending on the
1512  // dimension...
1513  std::set<unsigned> valid_indices;
1514 
1515  // Construct J^{-1}, A, and B matrices (see JWP's notes for details)
1516  // for cases in which the element dimension matches LIBMESH_DIM.
1517 #if LIBMESH_DIM==1
1518  RealTensor
1519  Jinv(dxidx_map[p], 0., 0.,
1520  0., 0., 0.,
1521  0., 0., 0.),
1522 
1523  A(d2xyzdxi2_map[p](0), 0., 0.,
1524  0., 0., 0.,
1525  0., 0., 0.),
1526 
1527  B(0., 0., 0.,
1528  0., 0., 0.,
1529  0., 0., 0.);
1530 
1532  dxi (dxidx_map[p], 0., 0.),
1533  deta (0., 0., 0.),
1534  dzeta(0., 0., 0.);
1535 
1536  // In 1D, we have only the xx second derivative
1537  valid_indices.insert(0);
1538 
1539 #elif LIBMESH_DIM==2
1540  RealTensor
1541  Jinv(dxidx_map[p], dxidy_map[p], 0.,
1542  detadx_map[p], detady_map[p], 0.,
1543  0., 0., 0.),
1544 
1545  A(d2xyzdxi2_map[p](0), d2xyzdeta2_map[p](0), 0.,
1546  d2xyzdxi2_map[p](1), d2xyzdeta2_map[p](1), 0.,
1547  0., 0., 0.),
1548 
1549  B(d2xyzdxideta_map[p](0), 0., 0.,
1550  d2xyzdxideta_map[p](1), 0., 0.,
1551  0., 0., 0.);
1552 
1554  dxi (dxidx_map[p], dxidy_map[p], 0.),
1555  deta (detadx_map[p], detady_map[p], 0.),
1556  dzeta(0., 0., 0.);
1557 
1558  // In 2D, we have xx, xy, and yy second derivatives
1559  const unsigned tmp[3] = {0,1,3};
1560  valid_indices.insert(tmp, tmp+3);
1561 
1562 #elif LIBMESH_DIM==3
1563  RealTensor
1564  Jinv(dxidx_map[p], dxidy_map[p], dxidz_map[p],
1565  detadx_map[p], detady_map[p], detadz_map[p],
1566  dzetadx_map[p], dzetady_map[p], dzetadz_map[p]),
1567 
1568  A(d2xyzdxi2_map[p](0), d2xyzdeta2_map[p](0), d2xyzdzeta2_map[p](0),
1569  d2xyzdxi2_map[p](1), d2xyzdeta2_map[p](1), d2xyzdzeta2_map[p](1),
1570  d2xyzdxi2_map[p](2), d2xyzdeta2_map[p](2), d2xyzdzeta2_map[p](2)),
1571 
1575 
1577  dxi (dxidx_map[p], dxidy_map[p], dxidz_map[p]),
1578  deta (detadx_map[p], detady_map[p], detadz_map[p]),
1579  dzeta(dzetadx_map[p], dzetady_map[p], dzetadz_map[p]);
1580 
1581  // In 3D, we have xx, xy, xz, yy, yz, and zz second derivatives
1582  const unsigned tmp[6] = {0,1,2,3,4,5};
1583  valid_indices.insert(tmp, tmp+6);
1584 
1585 #endif
1586 
1587  // For (s,t) in {(x,x), (x,y), (x,z), (y,y), (y,z), (z,z)}, compute the
1588  // vector of inverse map second derivatives [xi_{s t}, eta_{s t}, zeta_{s t}]
1589  unsigned ctr=0;
1590  for (unsigned s=0; s<3; ++s)
1591  for (unsigned t=s; t<3; ++t)
1592  {
1593  if (valid_indices.count(ctr))
1594  {
1596  v1(dxi(s)*dxi(t),
1597  deta(s)*deta(t),
1598  dzeta(s)*dzeta(t)),
1599 
1600  v2(dxi(s)*deta(t) + deta(s)*dxi(t),
1601  dxi(s)*dzeta(t) + dzeta(s)*dxi(t),
1602  deta(s)*dzeta(t) + dzeta(s)*deta(t));
1603 
1604  // Compute the inverse map second derivatives
1605  RealVectorValue v3 = -Jinv*(A*v1 + B*v2);
1606 
1607  // Store them in the appropriate locations in the class data structures
1608  d2xidxyz2_map[p][ctr] = v3(0);
1609 
1610  if (LIBMESH_DIM > 1)
1611  d2etadxyz2_map[p][ctr] = v3(1);
1612 
1613  if (LIBMESH_DIM > 2)
1614  d2zetadxyz2_map[p][ctr] = v3(2);
1615  }
1616 
1617  // Increment the counter
1618  ctr++;
1619  }
1620 #else
1621  // to avoid compiler warnings:
1622  libmesh_ignore(p);
1623 #endif // LIBMESH_ENABLE_SECOND_DERIVATIVES
1624 }
1625 
1626 
1627 
1628 Point FEMap::inverse_map (const unsigned int dim,
1629  const Elem * elem,
1630  const Point & physical_point,
1631  const Real tolerance,
1632  const bool secure,
1633  const bool
1634  extra_checks
1635  )
1636 {
1637  libmesh_assert(elem);
1638  libmesh_assert_greater_equal (tolerance, 0.);
1639 
1640  libmesh_ignore(extra_checks);
1641 
1642 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
1643 
1644  // TODO: possibly use the extra_checks parameter in InfFEMap::inverse_map() as well.
1645 
1646  if (elem->infinite())
1647  return InfFEMap::inverse_map(dim, elem, physical_point, tolerance,
1648  secure);
1649 #endif
1650 
1651  // Start logging the map inversion.
1652  LOG_SCOPE("inverse_map()", "FEMap");
1653 
1654  // How much did the point on the reference
1655  // element change by in this Newton step?
1656  Real inverse_map_error = 0.;
1657 
1658  // The point on the reference element. This is
1659  // the "initial guess" for Newton's method. The
1660  // centroid seems like a good idea, but computing
1661  // it is a little more intensive than, say taking
1662  // the zero point.
1663  //
1664  // Convergence should be insensitive of this choice
1665  // for "good" elements.
1666  Point p; // the zero point. No computation required
1667 
1668  // The number of iterations in the map inversion process.
1669  unsigned int cnt = 0;
1670 
1671  // The number of iterations after which we give up and declare
1672  // divergence
1673  const unsigned int max_cnt = 10;
1674 
1675  // The distance (in master element space) beyond which we give up
1676  // and declare divergence. This is no longer used...
1677  // Real max_step_length = 4.;
1678 
1679 
1680 
1681  // Newton iteration loop.
1682  do
1683  {
1684  // Where our current iterate \p p maps to.
1685  const Point physical_guess = map(dim, elem, p);
1686 
1687  // How far our current iterate is from the actual point.
1688  const Point delta = physical_point - physical_guess;
1689 
1690  // Increment in current iterate \p p, will be computed.
1691  Point dp;
1692 
1693 
1694  // The form of the map and how we invert it depends
1695  // on the dimension that we are in.
1696  switch (dim)
1697  {
1698  // ------------------------------------------------------------------
1699  // 0D map inversion is trivial
1700  case 0:
1701  {
1702  break;
1703  }
1704 
1705  // ------------------------------------------------------------------
1706  // 1D map inversion
1707  //
1708  // Here we find the point on a 1D reference element that maps to
1709  // the point \p physical_point in the domain. This is a bit tricky
1710  // since we do not want to assume that the point \p physical_point
1711  // is also in a 1D domain. In particular, this method might get
1712  // called on the edge of a 3D element, in which case
1713  // \p physical_point actually lives in 3D.
1714  case 1:
1715  {
1716  const Point dxi = map_deriv (dim, elem, 0, p);
1717 
1718  // Newton's method in this case looks like
1719  //
1720  // {X} - {X_n} = [J]*dp
1721  //
1722  // Where {X}, {X_n} are 3x1 vectors, [J] is a 3x1 matrix
1723  // d(x,y,z)/dxi, and we seek dp, a scalar. Since the above
1724  // system is either overdetermined or rank-deficient, we will
1725  // solve the normal equations for this system
1726  //
1727  // [J]^T ({X} - {X_n}) = [J]^T [J] {dp}
1728  //
1729  // which involves the trivial inversion of the scalar
1730  // G = [J]^T [J]
1731  const Real G = dxi*dxi;
1732 
1733  if (secure)
1734  libmesh_assert_greater (G, 0.);
1735 
1736  const Real Ginv = 1./G;
1737 
1738  const Real dxidelta = dxi*delta;
1739 
1740  dp(0) = Ginv*dxidelta;
1741 
1742  // No master elements have radius > 4, but sometimes we
1743  // can take a step that big while still converging
1744  // if (secure)
1745  // libmesh_assert_less (dp.size(), max_step_length);
1746 
1747  break;
1748  }
1749 
1750 
1751 
1752  // ------------------------------------------------------------------
1753  // 2D map inversion
1754  //
1755  // Here we find the point on a 2D reference element that maps to
1756  // the point \p physical_point in the domain. This is a bit tricky
1757  // since we do not want to assume that the point \p physical_point
1758  // is also in a 2D domain. In particular, this method might get
1759  // called on the face of a 3D element, in which case
1760  // \p physical_point actually lives in 3D.
1761  case 2:
1762  {
1763  const Point dxi = map_deriv (dim, elem, 0, p);
1764  const Point deta = map_deriv (dim, elem, 1, p);
1765 
1766  // Newton's method in this case looks like
1767  //
1768  // {X} - {X_n} = [J]*{dp}
1769  //
1770  // Where {X}, {X_n} are 3x1 vectors, [J] is a 3x2 matrix
1771  // d(x,y,z)/d(xi,eta), and we seek {dp}, a 2x1 vector. Since
1772  // the above system is either over-determined or rank-deficient,
1773  // we will solve the normal equations for this system
1774  //
1775  // [J]^T ({X} - {X_n}) = [J]^T [J] {dp}
1776  //
1777  // which involves the inversion of the 2x2 matrix
1778  // [G] = [J]^T [J]
1779  const Real
1780  G11 = dxi*dxi, G12 = dxi*deta,
1781  G21 = dxi*deta, G22 = deta*deta;
1782 
1783 
1784  const Real det = (G11*G22 - G12*G21);
1785 
1786  if (secure)
1787  libmesh_assert_not_equal_to (det, 0.);
1788 
1789  const Real inv_det = 1./det;
1790 
1791  const Real
1792  Ginv11 = G22*inv_det,
1793  Ginv12 = -G12*inv_det,
1794 
1795  Ginv21 = -G21*inv_det,
1796  Ginv22 = G11*inv_det;
1797 
1798 
1799  const Real dxidelta = dxi*delta;
1800  const Real detadelta = deta*delta;
1801 
1802  dp(0) = (Ginv11*dxidelta + Ginv12*detadelta);
1803  dp(1) = (Ginv21*dxidelta + Ginv22*detadelta);
1804 
1805  // No master elements have radius > 4, but sometimes we
1806  // can take a step that big while still converging
1807  // if (secure)
1808  // libmesh_assert_less (dp.size(), max_step_length);
1809 
1810  break;
1811  }
1812 
1813 
1814 
1815  // ------------------------------------------------------------------
1816  // 3D map inversion
1817  //
1818  // Here we find the point in a 3D reference element that maps to
1819  // the point \p physical_point in a 3D domain. Nothing special
1820  // has to happen here, since (unless the map is singular because
1821  // you have a BAD element) the map will be invertible and we can
1822  // apply Newton's method directly.
1823  case 3:
1824  {
1825  const Point dxi = map_deriv (dim, elem, 0, p);
1826  const Point deta = map_deriv (dim, elem, 1, p);
1827  const Point dzeta = map_deriv (dim, elem, 2, p);
1828 
1829  // Newton's method in this case looks like
1830  //
1831  // {X} = {X_n} + [J]*{dp}
1832  //
1833  // Where {X}, {X_n} are 3x1 vectors, [J] is a 3x3 matrix
1834  // d(x,y,z)/d(xi,eta,zeta), and we seek {dp}, a 3x1 vector.
1835  // Since the above system is nonsingular for invertible maps
1836  // we will solve
1837  //
1838  // {dp} = [J]^-1 ({X} - {X_n})
1839  //
1840  // which involves the inversion of the 3x3 matrix [J]
1841  libmesh_try
1842  {
1843  RealTensorValue(dxi(0), deta(0), dzeta(0),
1844  dxi(1), deta(1), dzeta(1),
1845  dxi(2), deta(2), dzeta(2)).solve(delta, dp);
1846  }
1847  libmesh_catch (ConvergenceFailure &)
1848  {
1849  // If we encountered a singular Jacobian, but are at
1850  // a singular node, return said singular node.
1851  const unsigned int local_singular_node =
1852  elem->local_singular_node(physical_point, tolerance);
1853  if (local_singular_node != invalid_uint)
1854  {
1855  libmesh_assert_less(local_singular_node, elem->n_nodes());
1856  return elem->master_point(local_singular_node);
1857  }
1858 
1859  // We encountered a singular Jacobian. The value of
1860  // dp is zero, since it was never changed during the
1861  // call to RealTensorValue::solve(). We don't want to
1862  // continue iterating until max_cnt since there is no
1863  // update to the Newton iterate, and we don't want to
1864  // print the inverse_map_error value since it will
1865  // confusingly be 0. Therefore, in the secure case we
1866  // need to throw an error message while in the !secure
1867  // case we can just return a far away point.
1868  if (secure)
1869  {
1870  libMesh::err << "ERROR: Newton scheme encountered a singular Jacobian in element: "
1871  << elem->id()
1872  << std::endl;
1873 
1874  elem->print_info(libMesh::err);
1875 
1876  libmesh_error_msg("Exiting...");
1877  }
1878  else
1879  {
1880  for (unsigned int i=0; i != dim; ++i)
1881  p(i) = 1e6;
1882  return p;
1883  }
1884  }
1885 
1886  // No master elements have radius > 4, but sometimes we
1887  // can take a step that big while still converging
1888  // if (secure)
1889  // libmesh_assert_less (dp.size(), max_step_length);
1890 
1891  break;
1892  }
1893 
1894 
1895  // Some other dimension?
1896  default:
1897  libmesh_error_msg("Invalid dim = " << dim);
1898  } // end switch(Dim), dp now computed
1899 
1900 
1901 
1902  // ||P_n+1 - P_n||
1903  inverse_map_error = dp.norm();
1904 
1905  // P_n+1 = P_n + dp
1906  p.add (dp);
1907 
1908  // Increment the iteration count.
1909  cnt++;
1910 
1911  // Watch for divergence of Newton's
1912  // method. Here's how it goes:
1913  // (1) For good elements, we expect convergence in 10
1914  // iterations, with no too-large steps.
1915  // - If called with (secure == true) and we have not yet converged
1916  // print out a warning message.
1917  // - If called with (secure == true) and we have not converged in
1918  // 20 iterations abort
1919  // (2) This method may be called in cases when the target point is not
1920  // inside the element and we have no business expecting convergence.
1921  // For these cases if we have not converged in 10 iterations forget
1922  // about it.
1923  if (cnt > max_cnt)
1924  {
1925  // Warn about divergence when secure is true - this
1926  // shouldn't happen
1927  if (secure)
1928  {
1929  // Print every time in devel/dbg modes
1930 #ifndef NDEBUG
1931  libmesh_here();
1932  libMesh::err << "WARNING: Newton scheme has not converged in "
1933  << cnt << " iterations:" << std::endl
1934  << " physical_point="
1935  << physical_point
1936  << " physical_guess="
1937  << physical_guess
1938  << " dp="
1939  << dp
1940  << " p="
1941  << p
1942  << " error=" << inverse_map_error
1943  << " in element " << elem->id()
1944  << std::endl;
1945 
1946  elem->print_info(libMesh::err);
1947 #else
1948  // In optimized mode, just print once that an inverse_map() call
1949  // had trouble converging its Newton iteration.
1950  libmesh_do_once(libMesh::err << "WARNING: At least one element took more than "
1951  << max_cnt
1952  << " iterations to converge in inverse_map()...\n"
1953  << "Rerun in devel/dbg mode for more details."
1954  << std::endl;);
1955 
1956 #endif // NDEBUG
1957 
1958  if (cnt > 2*max_cnt)
1959  {
1960  libMesh::err << "ERROR: Newton scheme FAILED to converge in "
1961  << cnt
1962  << " iterations in element "
1963  << elem->id()
1964  << " for physical point = "
1965  << physical_point
1966  << std::endl;
1967 
1968  elem->print_info(libMesh::err);
1969 
1970  libmesh_error_msg("Exiting...");
1971  }
1972  }
1973  // Return a far off point when secure is false - this
1974  // should only happen when we're trying to map a point
1975  // that's outside the element
1976  else
1977  {
1978  for (unsigned int i=0; i != dim; ++i)
1979  p(i) = 1e6;
1980 
1981  return p;
1982  }
1983  }
1984  }
1985  while (inverse_map_error > tolerance);
1986 
1987 
1988 
1989  // If we are in debug mode and the user requested it, do two extra sanity checks.
1990 #ifdef DEBUG
1991 
1992  if (extra_checks)
1993  {
1994  // Make sure the point \p p on the reference element actually
1995  // does map to the point \p physical_point within a tolerance.
1996 
1997  const Point check = map (dim, elem, p);
1998  const Point diff = physical_point - check;
1999 
2000  if (diff.norm() > tolerance)
2001  {
2002  libmesh_here();
2003  libMesh::err << "WARNING: diff is "
2004  << diff.norm()
2005  << std::endl
2006  << " point="
2007  << physical_point;
2008  libMesh::err << " local=" << check;
2009  libMesh::err << " lref= " << p;
2010 
2011  elem->print_info(libMesh::err);
2012  }
2013 
2014  // Make sure the point \p p on the reference element actually
2015  // is
2016 
2017  if (!elem->on_reference_element(p, 2*tolerance))
2018  {
2019  libmesh_here();
2020  libMesh::err << "WARNING: inverse_map of physical point "
2021  << physical_point
2022  << " is not on element." << '\n';
2023  elem->print_info(libMesh::err);
2024  }
2025  }
2026 
2027 #endif
2028 
2029  return p;
2030 }
2031 
2032 
2033 
2034 void FEMap::inverse_map (const unsigned int dim,
2035  const Elem * elem,
2036  const std::vector<Point> & physical_points,
2037  std::vector<Point> & reference_points,
2038  const Real tolerance,
2039  const bool secure,
2040  const bool extra_checks)
2041 {
2042 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
2043  if (elem->infinite())
2044  {
2045  // TODO: possibly use the extra_checks parameter in InfFEMap::inverse_map() as well.
2046  libmesh_ignore(extra_checks);
2047 
2048  return InfFEMap::inverse_map(dim, elem, physical_points, reference_points, tolerance, secure);
2049  }
2050 #endif
2051 
2052  // The number of points to find the
2053  // inverse map of
2054  const std::size_t n_points = physical_points.size();
2055 
2056  // Resize the vector to hold the points
2057  // on the reference element
2058  reference_points.resize(n_points);
2059 
2060  // Find the coordinates on the reference
2061  // element of each point in physical space
2062  for (std::size_t p=0; p<n_points; p++)
2063  reference_points[p] =
2064  inverse_map (dim, elem, physical_points[p], tolerance, secure, extra_checks);
2065 }
2066 
2067 
2068 
2069 Point FEMap::map (const unsigned int dim,
2070  const Elem * elem,
2071  const Point & reference_point)
2072 {
2073  libmesh_assert(elem);
2075 
2076 #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
2077  if (elem->infinite())
2078  return InfFEMap::map(dim, elem, reference_point);
2079 #endif
2080 
2081  Point p;
2082 
2083  const FEFamily mapping_family = FEMap::map_fe_type(*elem);
2084  const FEType fe_type (elem->default_order(), mapping_family);
2085 
2086  // Do not consider the Elem::p_level(), if any, when computing the
2087  // number of shape functions.
2088  const unsigned int n_sf = FEInterface::n_shape_functions(fe_type, /*extra_order=*/0, elem);
2089 
2090  FEInterface::shape_ptr shape_ptr =
2091  FEInterface::shape_function(fe_type, elem);
2092 
2093  // Lagrange basis functions are used for mapping
2094  for (unsigned int i=0; i<n_sf; i++)
2095  p.add_scaled (elem->point(i),
2096  shape_ptr(fe_type, elem, i, reference_point, false));
2097 
2098  return p;
2099 }
2100 
2101 
2102 
2103 Point FEMap::map_deriv (const unsigned int dim,
2104  const Elem * elem,
2105  const unsigned int j,
2106  const Point & reference_point)
2107 {
2108  libmesh_assert(elem);
2110 
2111  if (elem->infinite())
2112  libmesh_not_implemented();
2113 
2114  Point p;
2115 
2116  const FEFamily mapping_family = FEMap::map_fe_type(*elem);
2117  const FEType fe_type (elem->default_order(), mapping_family);
2118 
2119  // Do not consider the Elem::p_level(), if any, when computing the
2120  // number of shape functions.
2121  const unsigned int n_sf =
2122  FEInterface::n_shape_functions(fe_type, /*total_order=*/0, elem);
2123 
2124  FEInterface::shape_deriv_ptr shape_deriv_ptr =
2125  FEInterface::shape_deriv_function(fe_type, elem);
2126 
2127  // Lagrange basis functions are used for mapping
2128  for (unsigned int i=0; i<n_sf; i++)
2129  p.add_scaled (elem->point(i),
2130  shape_deriv_ptr(fe_type, elem, i, j, reference_point,
2131  /*add_p_level=*/false));
2132 
2133  return p;
2134 }
2135 
2136 
2137 
2138 // Explicit instantiation of FEMap member functions
2139 template LIBMESH_EXPORT void FEMap::init_reference_to_physical_map<0>( const std::vector<Point> &, const Elem *);
2140 template LIBMESH_EXPORT void FEMap::init_reference_to_physical_map<1>( const std::vector<Point> &, const Elem *);
2141 template LIBMESH_EXPORT void FEMap::init_reference_to_physical_map<2>( const std::vector<Point> &, const Elem *);
2142 template LIBMESH_EXPORT void FEMap::init_reference_to_physical_map<3>( const std::vector<Point> &, const Elem *);
2143 
2144 // subdivision elements are implemented only for 2D meshes & reimplement
2145 // the inverse_maps method separately
2147 
2148 } // 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:1283
FEFamily family
The type of finite element.
Definition: fe_type.h:221
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:2915
auto norm() const -> decltype(std::norm(T()))
Definition: type_vector.h:907
static shape_ptr shape_function(const unsigned int dim, const FEType &fe_t, const ElemType t)
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:310
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:1508
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:1439
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:1628
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:1197
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:1213
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:3120
dof_id_type id() const
Definition: dof_object.h:828
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:2146
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.
Definition: threads_tbb.h:167
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:1831
const Node * node_ptr(const unsigned int i) const
Definition: elem.h:2507
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:1364
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:2069
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:1500
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:1202
static Point map_deriv(const unsigned int dim, const Elem *elem, const unsigned int j, const Point &reference_point)
Definition: fe_map.C:2103
IntRange< unsigned short > node_index_range() const
Definition: elem.h:2683
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:1492
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:2453
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:117
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