LCOV - code coverage report
Current view: top level - src/fe - fe_abstract.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4538 (c3bcaa) with base 0a0a9d Lines: 302 474 63.7 %
Date: 2026-09-01 22:57:06 Functions: 7 13 53.8 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : // The libMesh Finite Element Library.
       2             : // Copyright (C) 2002-2026 Benjamin S. Kirk, John W. Peterson, Roy H. Stogner
       3             : 
       4             : // This library is free software; you can redistribute it and/or
       5             : // modify it under the terms of the GNU Lesser General Public
       6             : // License as published by the Free Software Foundation; either
       7             : // version 2.1 of the License, or (at your option) any later version.
       8             : 
       9             : // This library is distributed in the hope that it will be useful,
      10             : // but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             : // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      12             : // Lesser General Public License for more details.
      13             : 
      14             : // You should have received a copy of the GNU Lesser General Public
      15             : // License along with this library; if not, write to the Free Software
      16             : // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
      17             : 
      18             : // libmesh includes
      19             : #include "libmesh/fe.h"
      20             : #include "libmesh/libmesh_logging.h"
      21             : #include "libmesh/enum_elem_type.h"
      22             : #include "libmesh/boundary_info.h"
      23             : #include "libmesh/mesh_base.h"
      24             : #include "libmesh/dense_matrix.h"
      25             : #include "libmesh/dense_vector.h"
      26             : #include "libmesh/dof_map.h"
      27             : #include "libmesh/elem.h"
      28             : #include "libmesh/fe_interface.h"
      29             : #include "libmesh/numeric_vector.h"
      30             : #include "libmesh/periodic_boundaries.h"
      31             : #include "libmesh/periodic_boundary.h"
      32             : #include "libmesh/quadrature.h"
      33             : #include "libmesh/quadrature_gauss.h"
      34             : #include "libmesh/reference_elem.h"
      35             : #include "libmesh/remote_elem.h"
      36             : #include "libmesh/tensor_value.h"
      37             : #include "libmesh/threads.h"
      38             : #include "libmesh/enum_to_string.h"
      39             : 
      40             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
      41             : #include "libmesh/inf_fe.h"
      42             : #include "libmesh/fe_interface_macros.h"
      43             : #endif
      44             : 
      45             : namespace libMesh
      46             : {
      47             : 
      48    16954969 : FEAbstract::FEAbstract(const unsigned int d,
      49    16954969 :                        const FEType & fet) :
      50    15266874 :   _fe_map( FEMap::build(fet) ),
      51    15266874 :   dim(d),
      52    15266874 :   calculations_started(false),
      53    15266874 :   calculate_dual(false),
      54    15266874 :   calculate_default_dual_coeff(true),
      55    15266874 :   calculate_nothing(false),
      56    15266874 :   calculate_map(false),
      57    15266874 :   calculate_phi(false),
      58    15266874 :   calculate_dphi(false),
      59    15266874 :   calculate_d2phi(false),
      60    15266874 :   calculate_curl_phi(false),
      61    15266874 :   calculate_div_phi(false),
      62    15266874 :   calculate_dphiref(false),
      63    15266874 :   fe_type(fet),
      64    15266874 :   _elem_type(INVALID_ELEM),
      65    15266874 :   _elem(nullptr),
      66    15266874 :   _elem_p_level(0),
      67    15266874 :   _p_level(0),
      68    15266874 :   qrule(nullptr),
      69    15266874 :   shapes_on_quadrature(false),
      70    15266874 :   _n_total_qp(0),
      71    16954969 :   _add_p_level_in_reinit(true)
      72             : {
      73    16954969 : }
      74             : 
      75             : 
      76    15266874 : FEAbstract::~FEAbstract() = default;
      77             : 
      78             : 
      79    11091653 : std::unique_ptr<FEAbstract> FEAbstract::build(const unsigned int dim,
      80             :                                               const FEType & fet)
      81             : {
      82    11091653 :   switch (dim)
      83             :     {
      84             :       // 0D
      85      124440 :     case 0:
      86             :       {
      87      124440 :         switch (fet.family)
      88             :           {
      89           0 :           case CLOUGH:
      90           0 :             return std::make_unique<FE<0,CLOUGH>>(fet);
      91             : 
      92           0 :           case HERMITE:
      93           0 :             return std::make_unique<FE<0,HERMITE>>(fet);
      94             : 
      95       74680 :           case LAGRANGE:
      96       74680 :             return std::make_unique<FE<0,LAGRANGE>>(fet);
      97             : 
      98           0 :           case LAGRANGE_VEC:
      99           0 :             return std::make_unique<FE<0,LAGRANGE_VEC>>(fet);
     100             : 
     101        1680 :           case L2_LAGRANGE:
     102        1680 :             return std::make_unique<FE<0,L2_LAGRANGE>>(fet);
     103             : 
     104        1680 :           case L2_LAGRANGE_VEC:
     105        1680 :             return std::make_unique<FE<0,L2_LAGRANGE_VEC>>(fet);
     106             : 
     107           0 :           case HIERARCHIC_VEC:
     108           0 :             return std::make_unique<FE<0,HIERARCHIC_VEC>>(fet);
     109             : 
     110           0 :           case HIERARCHIC:
     111           0 :             return std::make_unique<FE<0,HIERARCHIC>>(fet);
     112             : 
     113        2272 :           case L2_HIERARCHIC:
     114        2272 :             return std::make_unique<FE<0,L2_HIERARCHIC>>(fet);
     115             : 
     116           0 :           case L2_HIERARCHIC_VEC:
     117           0 :             return std::make_unique<FE<0,L2_HIERARCHIC_VEC>>(fet);
     118             : 
     119        1680 :           case SIDE_HIERARCHIC:
     120        1680 :             return std::make_unique<FE<0,SIDE_HIERARCHIC>>(fet);
     121             : 
     122        6816 :           case MONOMIAL:
     123        6816 :             return std::make_unique<FE<0,MONOMIAL>>(fet);
     124             : 
     125           0 :           case MONOMIAL_VEC:
     126           0 :             return std::make_unique<FE<0,MONOMIAL_VEC>>(fet);
     127             : 
     128             : #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
     129           0 :           case SZABAB:
     130           0 :             return std::make_unique<FE<0,SZABAB>>(fet);
     131             : 
     132           0 :           case BERNSTEIN:
     133           0 :             return std::make_unique<FE<0,BERNSTEIN>>(fet);
     134             : 
     135       22024 :           case RATIONAL_BERNSTEIN:
     136       22024 :             return std::make_unique<FE<0,RATIONAL_BERNSTEIN>>(fet);
     137             : #endif
     138             : 
     139           0 :           case XYZ:
     140           0 :             return std::make_unique<FEXYZ<0>>(fet);
     141             : 
     142        7928 :           case SCALAR:
     143        7928 :             return std::make_unique<FEScalar<0>>(fet);
     144             : 
     145           0 :           case NEDELEC_ONE:
     146           0 :             return std::make_unique<FENedelecOne<0>>(fet);
     147             : 
     148        5680 :           case RAVIART_THOMAS:
     149        5680 :             return std::make_unique<FERaviartThomas<0>>(fet);
     150             : 
     151           0 :           case L2_RAVIART_THOMAS:
     152           0 :             return std::make_unique<FEL2RaviartThomas<0>>(fet);
     153             : 
     154           0 :           case SUBDIVISION:
     155           0 :             return std::make_unique<FESubdivision>(fet);
     156             : 
     157           0 :           default:
     158           0 :             libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
     159             :           }
     160             :       }
     161             :       // 1D
     162     1093544 :     case 1:
     163             :       {
     164     1093544 :         switch (fet.family)
     165             :           {
     166           0 :           case CLOUGH:
     167           0 :             return std::make_unique<FE<1,CLOUGH>>(fet);
     168             : 
     169      273696 :           case HERMITE:
     170      273696 :             return std::make_unique<FE<1,HERMITE>>(fet);
     171             : 
     172      128500 :           case LAGRANGE:
     173      128500 :             return std::make_unique<FE<1,LAGRANGE>>(fet);
     174             : 
     175           0 :           case LAGRANGE_VEC:
     176           0 :             return std::make_unique<FE<1,LAGRANGE_VEC>>(fet);
     177             : 
     178       44040 :           case L2_LAGRANGE:
     179       44040 :             return std::make_unique<FE<1,L2_LAGRANGE>>(fet);
     180             : 
     181           0 :           case L2_LAGRANGE_VEC:
     182           0 :             return std::make_unique<FE<1,L2_LAGRANGE_VEC>>(fet);
     183             : 
     184           0 :           case HIERARCHIC_VEC:
     185           0 :             return std::make_unique<FE<1,HIERARCHIC_VEC>>(fet);
     186             : 
     187      214876 :           case HIERARCHIC:
     188      214876 :             return std::make_unique<FE<1,HIERARCHIC>>(fet);
     189             : 
     190       73400 :           case L2_HIERARCHIC:
     191       73400 :             return std::make_unique<FE<1,L2_HIERARCHIC>>(fet);
     192             : 
     193           0 :           case L2_HIERARCHIC_VEC:
     194           0 :             return std::make_unique<FE<1,L2_HIERARCHIC_VEC>>(fet);
     195             : 
     196       48444 :           case SIDE_HIERARCHIC:
     197       48444 :             return std::make_unique<FE<1,SIDE_HIERARCHIC>>(fet);
     198             : 
     199      105068 :           case MONOMIAL:
     200      203936 :             return std::make_unique<FE<1,MONOMIAL>>(fet);
     201             : 
     202           0 :           case MONOMIAL_VEC:
     203           0 :             return std::make_unique<FE<1,MONOMIAL_VEC>>(fet);
     204             : 
     205             : #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
     206       58720 :           case SZABAB:
     207       58720 :             return std::make_unique<FE<1,SZABAB>>(fet);
     208             : 
     209       58720 :           case BERNSTEIN:
     210       58720 :             return std::make_unique<FE<1,BERNSTEIN>>(fet);
     211             : 
     212       29360 :           case RATIONAL_BERNSTEIN:
     213       29360 :             return std::make_unique<FE<1,RATIONAL_BERNSTEIN>>(fet);
     214             : #endif
     215             : 
     216       58720 :           case XYZ:
     217       58720 :             return std::make_unique<FEXYZ<1>>(fet);
     218             : 
     219           0 :           case SCALAR:
     220           0 :             return std::make_unique<FEScalar<1>>(fet);
     221             : 
     222           0 :           case NEDELEC_ONE:
     223           0 :             return std::make_unique<FENedelecOne<1>>(fet);
     224             : 
     225           0 :           case RAVIART_THOMAS:
     226           0 :             return std::make_unique<FERaviartThomas<1>>(fet);
     227             : 
     228           0 :           case L2_RAVIART_THOMAS:
     229           0 :             return std::make_unique<FEL2RaviartThomas<1>>(fet);
     230             : 
     231           0 :           case SUBDIVISION:
     232           0 :             return std::make_unique<FESubdivision>(fet);
     233             : 
     234           0 :           default:
     235           0 :             libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
     236             :           }
     237             :       }
     238             : 
     239             : 
     240             :       // 2D
     241     5785963 :     case 2:
     242             :       {
     243     5785963 :         switch (fet.family)
     244             :           {
     245      126204 :           case CLOUGH:
     246      126204 :             return std::make_unique<FE<2,CLOUGH>>(fet);
     247             : 
     248      112288 :           case HERMITE:
     249      112288 :             return std::make_unique<FE<2,HERMITE>>(fet);
     250             : 
     251     2910007 :           case LAGRANGE:
     252     2910007 :             return std::make_unique<FE<2,LAGRANGE>>(fet);
     253             : 
     254      122688 :           case LAGRANGE_VEC:
     255      122688 :             return std::make_unique<FE<2,LAGRANGE_VEC>>(fet);
     256             : 
     257      156976 :           case L2_LAGRANGE:
     258      156976 :             return std::make_unique<FE<2,L2_LAGRANGE>>(fet);
     259             : 
     260        8472 :           case L2_LAGRANGE_VEC:
     261        8472 :             return std::make_unique<FE<2,L2_LAGRANGE_VEC>>(fet);
     262             : 
     263           0 :           case HIERARCHIC_VEC:
     264           0 :             return std::make_unique<FE<2,HIERARCHIC_VEC>>(fet);
     265             : 
     266      897852 :           case HIERARCHIC:
     267      897852 :             return std::make_unique<FE<2,HIERARCHIC>>(fet);
     268             : 
     269      209016 :           case L2_HIERARCHIC:
     270      209016 :             return std::make_unique<FE<2,L2_HIERARCHIC>>(fet);
     271             : 
     272        6816 :           case L2_HIERARCHIC_VEC:
     273        6816 :             return std::make_unique<FE<2,L2_HIERARCHIC_VEC>>(fet);
     274             : 
     275      173648 :           case SIDE_HIERARCHIC:
     276      173648 :             return std::make_unique<FE<2,SIDE_HIERARCHIC>>(fet);
     277             : 
     278      396592 :           case MONOMIAL:
     279      396592 :             return std::make_unique<FE<2,MONOMIAL>>(fet);
     280             : 
     281        3408 :           case MONOMIAL_VEC:
     282        3408 :             return std::make_unique<FE<2,MONOMIAL_VEC>>(fet);
     283             : 
     284             : #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
     285      164416 :           case SZABAB:
     286      164416 :             return std::make_unique<FE<2,SZABAB>>(fet);
     287             : 
     288      161480 :           case BERNSTEIN:
     289      161480 :             return std::make_unique<FE<2,BERNSTEIN>>(fet);
     290             : 
     291       63040 :           case RATIONAL_BERNSTEIN:
     292       63040 :             return std::make_unique<FE<2,RATIONAL_BERNSTEIN>>(fet);
     293             : #endif
     294             : 
     295      244160 :           case XYZ:
     296      244160 :             return std::make_unique<FEXYZ<2>>(fet);
     297             : 
     298        6792 :           case SCALAR:
     299        6792 :             return std::make_unique<FEScalar<2>>(fet);
     300             : 
     301        7428 :           case NEDELEC_ONE:
     302        7428 :             return std::make_unique<FENedelecOne<2>>(fet);
     303             : 
     304       11280 :           case RAVIART_THOMAS:
     305       11280 :             return std::make_unique<FERaviartThomas<2>>(fet);
     306             : 
     307        3400 :           case L2_RAVIART_THOMAS:
     308        3400 :             return std::make_unique<FEL2RaviartThomas<2>>(fet);
     309             : 
     310           0 :           case SUBDIVISION:
     311           0 :             return std::make_unique<FESubdivision>(fet);
     312             : 
     313           0 :           default:
     314           0 :             libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
     315             :           }
     316             :       }
     317             : 
     318             : 
     319             :       // 3D
     320     4087706 :     case 3:
     321             :       {
     322     4087706 :         switch (fet.family)
     323             :           {
     324           0 :           case CLOUGH:
     325           0 :             libmesh_error_msg("ERROR: Clough-Tocher elements currently only support 1D and 2D");
     326             : 
     327       22020 :           case HERMITE:
     328       22020 :             return std::make_unique<FE<3,HERMITE>>(fet);
     329             : 
     330      954346 :           case LAGRANGE:
     331      954346 :             return std::make_unique<FE<3,LAGRANGE>>(fet);
     332             : 
     333      185736 :           case LAGRANGE_VEC:
     334      185736 :             return std::make_unique<FE<3,LAGRANGE_VEC>>(fet);
     335             : 
     336      321202 :           case L2_LAGRANGE:
     337      321202 :             return std::make_unique<FE<3,L2_LAGRANGE>>(fet);
     338             : 
     339        5112 :           case L2_LAGRANGE_VEC:
     340        5112 :             return std::make_unique<FE<3,L2_LAGRANGE_VEC>>(fet);
     341             : 
     342           0 :           case HIERARCHIC_VEC:
     343           0 :             return std::make_unique<FE<3,HIERARCHIC_VEC>>(fet);
     344             : 
     345      422628 :           case HIERARCHIC:
     346      422628 :             return std::make_unique<FE<3,HIERARCHIC>>(fet);
     347             : 
     348      436698 :           case L2_HIERARCHIC:
     349      436698 :             return std::make_unique<FE<3,L2_HIERARCHIC>>(fet);
     350             : 
     351        2556 :           case L2_HIERARCHIC_VEC:
     352        2556 :             return std::make_unique<FE<3,L2_HIERARCHIC_VEC>>(fet);
     353             : 
     354      242220 :           case SIDE_HIERARCHIC:
     355      242220 :             return std::make_unique<FE<3,SIDE_HIERARCHIC>>(fet);
     356             : 
     357      699774 :           case MONOMIAL:
     358      699774 :             return std::make_unique<FE<3,MONOMIAL>>(fet);
     359             : 
     360           0 :           case MONOMIAL_VEC:
     361           0 :             return std::make_unique<FE<3,MONOMIAL_VEC>>(fet);
     362             : 
     363             : #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
     364           0 :           case SZABAB:
     365           0 :             return std::make_unique<FE<3,SZABAB>>(fet);
     366             : 
     367      154140 :           case BERNSTEIN:
     368      154140 :             return std::make_unique<FE<3,BERNSTEIN>>(fet);
     369             : 
     370       70596 :           case RATIONAL_BERNSTEIN:
     371       70596 :             return std::make_unique<FE<3,RATIONAL_BERNSTEIN>>(fet);
     372             : #endif
     373             : 
     374      555612 :           case XYZ:
     375      555612 :             return std::make_unique<FEXYZ<3>>(fet);
     376             : 
     377        1704 :           case SCALAR:
     378        1704 :             return std::make_unique<FEScalar<3>>(fet);
     379             : 
     380        6612 :           case NEDELEC_ONE:
     381        6612 :             return std::make_unique<FENedelecOne<3>>(fet);
     382             : 
     383        4200 :           case RAVIART_THOMAS:
     384        4200 :             return std::make_unique<FERaviartThomas<3>>(fet);
     385             : 
     386        2550 :           case L2_RAVIART_THOMAS:
     387        2550 :             return std::make_unique<FEL2RaviartThomas<3>>(fet);
     388             : 
     389           0 :           default:
     390           0 :             libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
     391             :           }
     392             :       }
     393             : 
     394           0 :     default:
     395           0 :       libmesh_error_msg("Invalid dimension dim = " << dim);
     396             :     }
     397             : }
     398             : 
     399             : 
     400             : 
     401    34116366 : void FEAbstract::get_refspace_nodes(const ElemType itemType, std::vector<Point> & nodes)
     402             : {
     403    34116366 :   const unsigned int n_nodes = Elem::type_to_n_nodes_map[itemType];
     404    34116366 :   if (n_nodes == invalid_uint)
     405           0 :     libmesh_error_msg("Number of nodes is not well-defined for " <<
     406             :                       Utility::enum_to_string(itemType));
     407             : 
     408    34116366 :   nodes.resize(n_nodes);
     409             : 
     410             :   // For any element with a well-defined n_nodes we should also have a
     411             :   // well-defined reference element.
     412    34116366 :   const Elem & ref_elem = ReferenceElem::get(itemType);
     413             : 
     414   317539688 :   for (auto i : make_range(n_nodes))
     415   332262538 :     nodes[i] = ref_elem.point(i);
     416    34116366 : }
     417             : 
     418             : 
     419             : 
     420             : #ifdef LIBMESH_ENABLE_DEPRECATED
     421           0 : bool FEAbstract::on_reference_element(const Point & p, const ElemType t, const Real eps)
     422             : {
     423             :   // Use Elem::on_reference_element() instead
     424             :   libmesh_deprecated();
     425             : 
     426           0 :   libmesh_assert_greater_equal (eps, 0.);
     427             : 
     428           0 :   const Real xi   = p(0);
     429             : #if LIBMESH_DIM > 1
     430           0 :   const Real eta  = p(1);
     431             : #else
     432             :   const Real eta  = 0.;
     433             : #endif
     434             : #if LIBMESH_DIM > 2
     435           0 :   const Real zeta = p(2);
     436             : #else
     437             :   const Real zeta  = 0.;
     438             : #endif
     439             : 
     440           0 :   switch (t)
     441             :     {
     442           0 :     case NODEELEM:
     443             :       {
     444           0 :         return (!xi && !eta && !zeta);
     445             :       }
     446           0 :     case EDGE2:
     447             :     case EDGE3:
     448             :     case EDGE4:
     449             :       {
     450             :         // The reference 1D element is [-1,1].
     451           0 :         if ((xi >= -1.-eps) &&
     452           0 :             (xi <=  1.+eps))
     453           0 :           return true;
     454             : 
     455           0 :         return false;
     456             :       }
     457             : 
     458             : 
     459           0 :     case TRI3:
     460             :     case TRISHELL3:
     461             :     case TRI6:
     462             :     case TRI7:
     463             :       {
     464             :         // The reference triangle is isosceles
     465             :         // and is bound by xi=0, eta=0, and xi+eta=1.
     466           0 :         if ((xi  >= 0.-eps) &&
     467           0 :             (eta >= 0.-eps) &&
     468           0 :             ((xi + eta) <= 1.+eps))
     469           0 :           return true;
     470             : 
     471           0 :         return false;
     472             :       }
     473             : 
     474             : 
     475           0 :     case QUAD4:
     476             :     case QUADSHELL4:
     477             :     case QUAD8:
     478             :     case QUADSHELL8:
     479             :     case QUAD9:
     480             :     case QUADSHELL9:
     481             :       {
     482             :         // The reference quadrilateral element is [-1,1]^2.
     483           0 :         if ((xi  >= -1.-eps) &&
     484           0 :             (xi  <=  1.+eps) &&
     485           0 :             (eta >= -1.-eps) &&
     486           0 :             (eta <=  1.+eps))
     487           0 :           return true;
     488             : 
     489           0 :         return false;
     490             :       }
     491             : 
     492             : 
     493           0 :     case TET4:
     494             :     case TET10:
     495             :     case TET14:
     496             :       {
     497             :         // The reference tetrahedral is isosceles
     498             :         // and is bound by xi=0, eta=0, zeta=0,
     499             :         // and xi+eta+zeta=1.
     500           0 :         if ((xi   >= 0.-eps) &&
     501           0 :             (eta  >= 0.-eps) &&
     502           0 :             (zeta >= 0.-eps) &&
     503           0 :             ((xi + eta + zeta) <= 1.+eps))
     504           0 :           return true;
     505             : 
     506           0 :         return false;
     507             :       }
     508             : 
     509             : 
     510           0 :     case HEX8:
     511             :     case HEX20:
     512             :     case HEX27:
     513             :       {
     514             :         /*
     515             :           if ((xi   >= -1.) &&
     516             :           (xi   <=  1.) &&
     517             :           (eta  >= -1.) &&
     518             :           (eta  <=  1.) &&
     519             :           (zeta >= -1.) &&
     520             :           (zeta <=  1.))
     521             :           return true;
     522             :         */
     523             : 
     524             :         // The reference hexahedral element is [-1,1]^3.
     525           0 :         if ((xi   >= -1.-eps) &&
     526           0 :             (xi   <=  1.+eps) &&
     527           0 :             (eta  >= -1.-eps) &&
     528           0 :             (eta  <=  1.+eps) &&
     529           0 :             (zeta >= -1.-eps) &&
     530           0 :             (zeta <=  1.+eps))
     531             :           {
     532             :             //    libMesh::out << "Strange Point:\n";
     533             :             //    p.print();
     534           0 :             return true;
     535             :           }
     536             : 
     537           0 :         return false;
     538             :       }
     539             : 
     540           0 :     case PRISM6:
     541             :     case PRISM15:
     542             :     case PRISM18:
     543             :     case PRISM20:
     544             :     case PRISM21:
     545             :       {
     546             :         // Figure this one out...
     547             :         // inside the reference triangle with zeta in [-1,1]
     548           0 :         if ((xi   >=  0.-eps) &&
     549           0 :             (eta  >=  0.-eps) &&
     550           0 :             (zeta >= -1.-eps) &&
     551           0 :             (zeta <=  1.+eps) &&
     552           0 :             ((xi + eta) <= 1.+eps))
     553           0 :           return true;
     554             : 
     555           0 :         return false;
     556             :       }
     557             : 
     558             : 
     559           0 :     case PYRAMID5:
     560             :     case PYRAMID13:
     561             :     case PYRAMID14:
     562             :     case PYRAMID18:
     563             :       {
     564             :         // Check that the point is on the same side of all the faces
     565             :         // by testing whether:
     566             :         //
     567             :         // n_i.(x - x_i) <= 0
     568             :         //
     569             :         // for each i, where:
     570             :         //   n_i is the outward normal of face i,
     571             :         //   x_i is a point on face i.
     572           0 :         if ((-eta - 1. + zeta <= 0.+eps) &&
     573           0 :             (  xi - 1. + zeta <= 0.+eps) &&
     574           0 :             ( eta - 1. + zeta <= 0.+eps) &&
     575           0 :             ( -xi - 1. + zeta <= 0.+eps) &&
     576           0 :             (            zeta >= 0.-eps))
     577           0 :           return true;
     578             : 
     579           0 :         return false;
     580             :       }
     581             : 
     582             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
     583           0 :     case INFHEX8:
     584             :     case INFHEX16:
     585             :     case INFHEX18:
     586             :       {
     587             :         // The reference infhex8 is a [-1,1]^3.
     588           0 :         if ((xi   >= -1.-eps) &&
     589           0 :             (xi   <=  1.+eps) &&
     590           0 :             (eta  >= -1.-eps) &&
     591           0 :             (eta  <=  1.+eps) &&
     592           0 :             (zeta >= -1.-eps) &&
     593           0 :             (zeta <=  1.+eps))
     594             :           {
     595           0 :             return true;
     596             :           }
     597           0 :         return false;
     598             :       }
     599             : 
     600           0 :     case INFPRISM6:
     601             :     case INFPRISM12:
     602             :       {
     603             :         // inside the reference triangle with zeta in [-1,1]
     604           0 :         if ((xi   >=  0.-eps) &&
     605           0 :             (eta  >=  0.-eps) &&
     606           0 :             (zeta >= -1.-eps) &&
     607           0 :             (zeta <=  1.+eps) &&
     608           0 :             ((xi + eta) <= 1.+eps))
     609             :           {
     610           0 :             return true;
     611             :           }
     612             : 
     613           0 :         return false;
     614             :       }
     615             : #endif
     616             : 
     617           0 :     default:
     618           0 :       libmesh_error_msg("ERROR: Unknown element type " << Utility::enum_to_string(t));
     619             :     }
     620             : 
     621             :   // If we get here then the point is _not_ in the
     622             :   // reference element.   Better return false.
     623             : 
     624             :   return false;
     625             : }
     626             : #endif // LIBMESH_ENABLE_DEPRECATED
     627             : 
     628             : 
     629             : 
     630           0 : void FEAbstract::print_JxW(std::ostream & os) const
     631             : {
     632           0 :   this->_fe_map->print_JxW(os);
     633           0 : }
     634             : 
     635             : 
     636             : 
     637           0 : void FEAbstract::print_xyz(std::ostream & os) const
     638             : {
     639           0 :   this->_fe_map->print_xyz(os);
     640           0 : }
     641             : 
     642             : 
     643           0 : void FEAbstract::print_info(std::ostream & os) const
     644             : {
     645           0 :   os << "phi[i][j]: Shape function i at quadrature pt. j" << std::endl;
     646           0 :   this->print_phi(os);
     647             : 
     648           0 :   os << "dphi[i][j]: Shape function i's gradient at quadrature pt. j" << std::endl;
     649           0 :   this->print_dphi(os);
     650             : 
     651           0 :   os << "XYZ locations of the quadrature pts." << std::endl;
     652           0 :   this->print_xyz(os);
     653             : 
     654           0 :   os << "Values of JxW at the quadrature pts." << std::endl;
     655           0 :   this->print_JxW(os);
     656           0 : }
     657             : 
     658             : 
     659           0 : std::ostream & operator << (std::ostream & os, const FEAbstract & fe)
     660             : {
     661           0 :   fe.print_info(os);
     662           0 :   return os;
     663             : }
     664             : 
     665             : 
     666             : 
     667             : #ifdef LIBMESH_ENABLE_AMR
     668             : 
     669             : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
     670     1029068 : void FEAbstract::compute_node_constraints (NodeConstraints & constraints,
     671             :                                            const Elem * elem)
     672             : {
     673      514534 :   libmesh_assert(elem);
     674             : 
     675     1029068 :   const unsigned int Dim = elem->dim();
     676             : 
     677             :   // Only constrain elements in 2,3D.
     678     1029068 :   if (Dim == 1)
     679       96308 :     return;
     680             : 
     681             :   // Only constrain active and ancestor elements
     682     1014736 :   if (elem->subactive())
     683       39932 :     return;
     684             : 
     685             : 
     686             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
     687      934872 :   if (elem->infinite())
     688             :     {
     689        2112 :       const FEType fe_t(elem->default_order(), FEMap::map_fe_type(*elem));
     690             : 
     691             :       // expand the infinite_compute_constraint in its template-arguments.
     692        2112 :       switch(Dim)
     693             :       {
     694           0 :          case 2:
     695             :             {
     696           0 :             inf_fe_family_mapping_switch(2, inf_compute_node_constraints (constraints, elem) , ,; break;);
     697           0 :             break;
     698             :           }
     699        1056 :          case 3:
     700             :             {
     701        2112 :             inf_fe_family_mapping_switch(3, inf_compute_node_constraints (constraints, elem) , ,; break;);
     702        1056 :             break;
     703             :             }
     704           0 :          default:
     705           0 :            libmesh_error_msg("Invalid dim = " << Dim);
     706             :       }
     707        1056 :       return;
     708             :     }
     709             : 
     710             : #endif
     711      932760 :   const FEFamily mapping_family = FEMap::map_fe_type(*elem);
     712      932760 :   const FEType fe_type(elem->default_side_order(), mapping_family);
     713             : 
     714             :   // Pull objects out of the loop to reduce heap operations
     715      932760 :   std::vector<const Node *> my_nodes, parent_nodes;
     716      932760 :   std::unique_ptr<const Elem> my_side, parent_side;
     717             : 
     718             :   // Look at the element faces.  Check to see if we need to
     719             :   // build constraints.
     720     4637580 :   for (auto s : elem->side_index_range())
     721     7293068 :     if (elem->neighbor_ptr(s) != nullptr &&
     722     3471676 :         elem->neighbor_ptr(s) != remote_elem)
     723     3471676 :       if (elem->neighbor_ptr(s)->level() < elem->level()) // constrain dofs shared between
     724             :         {                                                 // this element and ones coarser
     725             :           // than this element.
     726             :           // Get pointers to the elements of interest and its parent.
     727      117000 :           const Elem * parent = elem->parent();
     728             : 
     729             :           // This can't happen...  Only level-0 elements have nullptr
     730             :           // parents, and no level-0 elements can be at a higher
     731             :           // level than their neighbors!
     732       58500 :           libmesh_assert(parent);
     733             : 
     734      117000 :           elem->build_side_ptr(my_side, s);
     735      117000 :           parent->build_side_ptr(parent_side, s);
     736             : 
     737      117000 :           const unsigned int n_side_nodes = my_side->n_nodes();
     738             : 
     739       58500 :           my_nodes.clear();
     740      117000 :           my_nodes.reserve (n_side_nodes);
     741       58500 :           parent_nodes.clear();
     742      117000 :           parent_nodes.reserve (n_side_nodes);
     743             : 
     744      437380 :           for (unsigned int n=0; n != n_side_nodes; ++n)
     745      480570 :             my_nodes.push_back(my_side->node_ptr(n));
     746             : 
     747      437380 :           for (unsigned int n=0; n != n_side_nodes; ++n)
     748      480570 :             parent_nodes.push_back(parent_side->node_ptr(n));
     749             : 
     750      378880 :           for (unsigned int my_side_n=0;
     751      437380 :                my_side_n < n_side_nodes;
     752             :                my_side_n++)
     753             :             {
     754             :               // We can have an FE type that supports an order
     755             :               // partially, such that sides do not support the same
     756             :               // order.  E.g. we say that a LAGRANGE PRISM21 supports
     757             :               // "third" order to distinguish its shape functions from
     758             :               // a PRISM18, but the QUAD9 sides will still only
     759             :               // support second order.
     760      320380 :               FEType side_fe_type = fe_type;
     761             :               const int side_max_order =
     762      320380 :                 FEInterface::max_order(fe_type, my_side->type());
     763             : 
     764      320380 :               if ((int)fe_type.order > side_max_order)
     765        2736 :                 side_fe_type.order = side_max_order;
     766             : 
     767             :               // Do not use the p_level(), if any, that is inherited by the side.
     768      160190 :               libmesh_assert_less
     769             :                 (my_side_n,
     770             :                  FEInterface::n_dofs(side_fe_type, /*extra_order=*/0,
     771             :                                      my_side.get()));
     772             : 
     773      320380 :               const Node * my_node = my_nodes[my_side_n];
     774             : 
     775             :               // The support point of the DOF
     776      320380 :               const Point & support_point = *my_node;
     777             : 
     778             :               // Figure out where my node lies on their reference element.
     779             :               const Point mapped_point = FEMap::inverse_map(Dim-1,
     780             :                                                             parent_side.get(),
     781      320380 :                                                             support_point);
     782             : 
     783             :               // Compute the parent's side shape function values.
     784     1152266 :               for (unsigned int their_side_n=0;
     785     1312456 :                    their_side_n < n_side_nodes;
     786             :                    their_side_n++)
     787             :                 {
     788             :                   // Do not use the p_level(), if any, that is inherited by the side.
     789      496038 :                   libmesh_assert_less
     790             :                     (their_side_n,
     791             :                      FEInterface::n_dofs(side_fe_type,
     792             :                                          /*extra_order=*/0,
     793             :                                          parent_side.get()));
     794             : 
     795     1488114 :                   const Node * their_node = parent_nodes[their_side_n];
     796      496038 :                   libmesh_assert(their_node);
     797             : 
     798             :                   // Do not use the p_level(), if any, that is inherited by the side.
     799      992076 :                   const Real their_value = FEInterface::shape(side_fe_type,
     800             :                                                               /*extra_order=*/0,
     801             :                                                               parent_side.get(),
     802             :                                                               their_side_n,
     803      992076 :                                                               mapped_point);
     804             : 
     805      496038 :                   const Real their_mag = std::abs(their_value);
     806             : #ifdef DEBUG
     807             :                   // Protect for the case u_i ~= u_j,
     808             :                   // in which case i better equal j.
     809      496038 :                   if (their_mag > 0.999)
     810             :                     {
     811       81714 :                       libmesh_assert_equal_to (my_node, their_node);
     812       81714 :                       libmesh_assert_less (std::abs(their_value - 1.), 0.001);
     813             :                     }
     814             :                   else
     815             : #endif
     816             :                     // To make nodal constraints useful for constructing
     817             :                     // sparsity patterns faster, we need to get EVERY
     818             :                     // POSSIBLE constraint coupling identified, even if
     819             :                     // there is no coupling in the isoparametric
     820             :                     // Lagrange case.
     821      910362 :                     if (their_mag < 1.e-5)
     822             :                       {
     823             :                         // since we may be running this method concurrently
     824             :                         // on multiple threads we need to acquire a lock
     825             :                         // before modifying the shared constraint_row object.
     826      210986 :                         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
     827             : 
     828             :                         // A reference to the constraint row.
     829      421972 :                         NodeConstraintRow & constraint_row = constraints[my_node].first;
     830             : 
     831      421972 :                         constraint_row.emplace(their_node, 0.);
     832             :                       }
     833             :                   // To get nodal coordinate constraints right, only
     834             :                   // add non-zero and non-identity values for Lagrange
     835             :                   // basis functions.
     836             :                     else // (1.e-5 <= their_mag <= .999)
     837             :                       {
     838             :                         // since we may be running this method concurrently
     839             :                         // on multiple threads we need to acquire a lock
     840             :                         // before modifying the shared constraint_row object.
     841      406676 :                         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
     842             : 
     843             :                         // A reference to the constraint row.
     844      488390 :                         NodeConstraintRow & constraint_row = constraints[my_node].first;
     845             : 
     846      203338 :                         constraint_row.emplace(their_node, their_value);
     847             :                       }
     848             :                 }
     849             :             }
     850             :         }
     851             : }
     852             : 
     853             : #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
     854             : 
     855             : #endif // #ifdef LIBMESH_ENABLE_AMR
     856             : 
     857             : 
     858             : 
     859             : #ifdef LIBMESH_ENABLE_PERIODIC
     860             : 
     861             : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
     862      129724 : void FEAbstract::compute_periodic_node_constraints (NodeConstraints & constraints,
     863             :                                                     const PeriodicBoundaries & boundaries,
     864             :                                                     const MeshBase & mesh,
     865             :                                                     const PointLocatorBase * point_locator,
     866             :                                                     const Elem * elem)
     867             : {
     868             :   // Only bother if we truly have periodic boundaries
     869      129724 :   if (boundaries.empty())
     870       38982 :     return;
     871             : 
     872       64862 :   libmesh_assert(elem);
     873             : 
     874             :   // Only constrain active elements with this method
     875       64862 :   if (!elem->active())
     876       19491 :     return;
     877             : 
     878       90742 :   const unsigned int Dim = elem->dim();
     879             : 
     880       90742 :   const FEFamily mapping_family = FEMap::map_fe_type(*elem);
     881       90742 :   const FEType fe_type(elem->default_side_order(), mapping_family);
     882             : 
     883             :   // Pull objects out of the loop to reduce heap operations
     884       90742 :   std::vector<const Node *> my_nodes, neigh_nodes;
     885       90742 :   std::unique_ptr<const Elem> my_side, neigh_side;
     886             : 
     887             :   // Look at the element faces.  Check to see if we need to
     888             :   // build constraints.
     889       90742 :   std::vector<boundary_id_type> bc_ids;
     890      441726 :   for (auto s : elem->side_index_range())
     891             :     {
     892      526476 :       if (elem->neighbor_ptr(s))
     893      172162 :         continue;
     894             : 
     895        6660 :       mesh.get_boundary_info().boundary_ids (elem, s, bc_ids);
     896       12272 :       for (const auto & boundary_id : bc_ids)
     897             :         {
     898        5612 :           const PeriodicBoundaryBase * periodic = boundaries.boundary(boundary_id);
     899        5612 :           if (periodic)
     900             :             {
     901        2644 :               libmesh_assert(point_locator);
     902             : 
     903             :               // Get pointers to the element's neighbor.
     904             :               unsigned int s_neigh;
     905        5288 :               const Elem * neigh = boundaries.neighbor(boundary_id, *point_locator, elem, s, &s_neigh);
     906             : 
     907        5288 :               libmesh_error_msg_if
     908             :                 (!neigh, "PeriodicBoundaries can't find a periodic neighbor for element " <<
     909             :                          elem->id() << " side " << s);
     910             : 
     911             :               // h refinement constraints:
     912             :               // constrain dofs shared between
     913             :               // this element and ones as coarse
     914             :               // as or coarser than this element.
     915        5288 :               if (neigh->level() <= elem->level())
     916             :                 {
     917             : #ifdef LIBMESH_ENABLE_AMR
     918        2196 :                   libmesh_assert(neigh->active());
     919             : #endif // #ifdef LIBMESH_ENABLE_AMR
     920             : 
     921        4392 :                   elem->build_side_ptr(my_side, s);
     922        4392 :                   neigh->build_side_ptr(neigh_side, s_neigh);
     923             : 
     924        4392 :                   const unsigned int n_side_nodes = my_side->n_nodes();
     925             : 
     926        2196 :                   my_nodes.clear();
     927        4392 :                   my_nodes.reserve (n_side_nodes);
     928        2196 :                   neigh_nodes.clear();
     929        4392 :                   neigh_nodes.reserve (n_side_nodes);
     930             : 
     931       14000 :                   for (unsigned int n=0; n != n_side_nodes; ++n)
     932       14412 :                     my_nodes.push_back(my_side->node_ptr(n));
     933             : 
     934       14000 :                   for (unsigned int n=0; n != n_side_nodes; ++n)
     935       14412 :                     neigh_nodes.push_back(neigh_side->node_ptr(n));
     936             : 
     937             :                   // Make sure we're not adding recursive constraints
     938             :                   // due to the redundancy in the way we add periodic
     939             :                   // boundary constraints, or adding constraints to
     940             :                   // nodes that already have AMR constraints
     941        6588 :                   std::vector<bool> skip_constraint(n_side_nodes, false);
     942             : 
     943       11804 :                   for (unsigned int my_side_n=0;
     944       14000 :                        my_side_n < n_side_nodes;
     945             :                        my_side_n++)
     946             :                     {
     947             :                       // Do not use the p_level(), if any, that is inherited by the side.
     948        4804 :                       libmesh_assert_less (my_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, my_side.get()));
     949             : 
     950       14412 :                       const Node * my_node = my_nodes[my_side_n];
     951             : 
     952             :                       // If we've already got a constraint on this
     953             :                       // node, then the periodic constraint is
     954             :                       // redundant
     955             :                       {
     956        4804 :                         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
     957             : 
     958        4804 :                         if (constraints.count(my_node))
     959             :                           {
     960        3896 :                             skip_constraint[my_side_n] = true;
     961        1948 :                             continue;
     962             :                           }
     963             :                       }
     964             : 
     965             :                       // Compute the neighbors's side shape function values.
     966       16496 :                       for (unsigned int their_side_n=0;
     967       19352 :                            their_side_n < n_side_nodes;
     968             :                            their_side_n++)
     969             :                         {
     970             :                           // Do not use the p_level(), if any, that is inherited by the side.
     971        6820 :                           libmesh_assert_less (their_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, neigh_side.get()));
     972             : 
     973       20460 :                           const Node * their_node = neigh_nodes[their_side_n];
     974             : 
     975             :                           // If there's a constraint on an opposing node,
     976             :                           // we need to see if it's constrained by
     977             :                           // *our side* making any periodic constraint
     978             :                           // on us recursive
     979             :                           {
     980        6820 :                             Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
     981             : 
     982        6820 :                             if (!constraints.count(their_node))
     983        4152 :                               continue;
     984             : 
     985             :                             const NodeConstraintRow & their_constraint_row =
     986        5336 :                               constraints[their_node].first;
     987             : 
     988       19684 :                             for (unsigned int orig_side_n=0;
     989       22352 :                                  orig_side_n < n_side_nodes;
     990             :                                  orig_side_n++)
     991             :                               {
     992             :                                 // Do not use the p_level(), if any, that is inherited by the side.
     993        8508 :                                 libmesh_assert_less (orig_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, my_side.get()));
     994             : 
     995       25524 :                                 const Node * orig_node = my_nodes[orig_side_n];
     996             : 
     997        8508 :                                 if (their_constraint_row.count(orig_node))
     998       10732 :                                   skip_constraint[orig_side_n] = true;
     999             :                               }
    1000             :                           }
    1001             :                         }
    1002             :                     }
    1003       11804 :                   for (unsigned int my_side_n=0;
    1004       14000 :                        my_side_n < n_side_nodes;
    1005             :                        my_side_n++)
    1006             :                     {
    1007             :                       // Do not use the p_level(), if any, that is inherited by the side.
    1008        4804 :                       libmesh_assert_less (my_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, my_side.get()));
    1009             : 
    1010       14412 :                       if (skip_constraint[my_side_n])
    1011        5596 :                         continue;
    1012             : 
    1013        4012 :                       const Node * my_node = my_nodes[my_side_n];
    1014             : 
    1015             :                       // Figure out where my node lies on their reference element.
    1016        4012 :                       const Point neigh_point = periodic->get_corresponding_pos(*my_node);
    1017             : 
    1018             :                       // Figure out where my node lies on their reference element.
    1019             :                       const Point mapped_point =
    1020             :                         FEMap::inverse_map(Dim-1, neigh_side.get(),
    1021        4012 :                                            neigh_point);
    1022             : 
    1023       10590 :                       for (unsigned int their_side_n=0;
    1024       12596 :                            their_side_n < n_side_nodes;
    1025             :                            their_side_n++)
    1026             :                         {
    1027             :                           // Do not use the p_level(), if any, that is inherited by the side.
    1028        4292 :                           libmesh_assert_less (their_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, neigh_side.get()));
    1029             : 
    1030       12876 :                           const Node * their_node = neigh_nodes[their_side_n];
    1031        4292 :                           libmesh_assert(their_node);
    1032             : 
    1033             :                           // Do not use the p_level(), if any, that is inherited by the side.
    1034        8584 :                           const Real their_value = FEInterface::shape(fe_type,
    1035             :                                                                       /*extra_order=*/0,
    1036             :                                                                       neigh_side.get(),
    1037             :                                                                       their_side_n,
    1038        8584 :                                                                       mapped_point);
    1039             : 
    1040             :                           // since we may be running this method concurrently
    1041             :                           // on multiple threads we need to acquire a lock
    1042             :                           // before modifying the shared constraint_row object.
    1043             :                           {
    1044        8584 :                             Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1045             : 
    1046             :                             NodeConstraintRow & constraint_row =
    1047        8584 :                               constraints[my_node].first;
    1048             : 
    1049        4292 :                             constraint_row.emplace(their_node, their_value);
    1050             :                           }
    1051             :                         }
    1052             :                     }
    1053             :                 }
    1054             :             }
    1055             :         }
    1056             :     }
    1057             : }
    1058             : #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
    1059             : 
    1060             : #endif // LIBMESH_ENABLE_PERIODIC
    1061             : 
    1062             : 
    1063     2156439 : unsigned int FEAbstract::n_quadrature_points () const
    1064             : {
    1065      240304 :   if (this->shapes_on_quadrature)
    1066             :     {
    1067      240288 :       libmesh_assert(this->qrule);
    1068      240288 :       libmesh_assert_equal_to(this->qrule->n_points(),
    1069             :                               this->_n_total_qp);
    1070             :     }
    1071     2156439 :   return this->_n_total_qp;
    1072             : }
    1073             : 
    1074             : } // namespace libMesh

Generated by: LCOV version 1.14