LCOV - code coverage report
Current view: top level - src/fe - fe_abstract.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4229 (6a9aeb) with base 727f46 Lines: 408 611 66.8 %
Date: 2025-08-19 19:27:09 Functions: 7 13 53.8 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : // 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/remote_elem.h"
      35             : #include "libmesh/tensor_value.h"
      36             : #include "libmesh/threads.h"
      37             : #include "libmesh/enum_to_string.h"
      38             : 
      39             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
      40             : #include "libmesh/inf_fe.h"
      41             : #include "libmesh/fe_interface_macros.h"
      42             : #endif
      43             : 
      44             : namespace libMesh
      45             : {
      46             : 
      47    15326404 : FEAbstract::FEAbstract(const unsigned int d,
      48    15326404 :                        const FEType & fet) :
      49    13587717 :   _fe_map( FEMap::build(fet) ),
      50    13587717 :   dim(d),
      51    13587717 :   calculations_started(false),
      52    13587717 :   calculate_dual(false),
      53    13587717 :   calculate_default_dual_coeff(true),
      54    13587717 :   calculate_nothing(false),
      55    13587717 :   calculate_map(false),
      56    13587717 :   calculate_phi(false),
      57    13587717 :   calculate_dphi(false),
      58    13587717 :   calculate_d2phi(false),
      59    13587717 :   calculate_curl_phi(false),
      60    13587717 :   calculate_div_phi(false),
      61    13587717 :   calculate_dphiref(false),
      62    13587717 :   fe_type(fet),
      63    13587717 :   _elem_type(INVALID_ELEM),
      64    13587717 :   _elem(nullptr),
      65    13587717 :   _elem_p_level(0),
      66    13587717 :   _p_level(0),
      67    13587717 :   qrule(nullptr),
      68    13587717 :   shapes_on_quadrature(false),
      69    13587717 :   _n_total_qp(0),
      70    15326404 :   _add_p_level_in_reinit(true)
      71             : {
      72    15326404 : }
      73             : 
      74             : 
      75    13587717 : FEAbstract::~FEAbstract() = default;
      76             : 
      77             : 
      78     9973585 : std::unique_ptr<FEAbstract> FEAbstract::build(const unsigned int dim,
      79             :                                               const FEType & fet)
      80             : {
      81     9973585 :   switch (dim)
      82             :     {
      83             :       // 0D
      84      125080 :     case 0:
      85             :       {
      86      125080 :         switch (fet.family)
      87             :           {
      88           0 :           case CLOUGH:
      89           0 :             return std::make_unique<FE<0,CLOUGH>>(fet);
      90             : 
      91           0 :           case HERMITE:
      92           0 :             return std::make_unique<FE<0,HERMITE>>(fet);
      93             : 
      94       74752 :           case LAGRANGE:
      95       74752 :             return std::make_unique<FE<0,LAGRANGE>>(fet);
      96             : 
      97           0 :           case LAGRANGE_VEC:
      98           0 :             return std::make_unique<FE<0,LAGRANGE_VEC>>(fet);
      99             : 
     100        1680 :           case L2_LAGRANGE:
     101        1680 :             return std::make_unique<FE<0,L2_LAGRANGE>>(fet);
     102             : 
     103        1680 :           case L2_LAGRANGE_VEC:
     104        1680 :             return std::make_unique<FE<0,L2_LAGRANGE_VEC>>(fet);
     105             : 
     106           0 :           case HIERARCHIC_VEC:
     107           0 :             return std::make_unique<FE<0,HIERARCHIC_VEC>>(fet);
     108             : 
     109           0 :           case HIERARCHIC:
     110           0 :             return std::make_unique<FE<0,HIERARCHIC>>(fet);
     111             : 
     112        2272 :           case L2_HIERARCHIC:
     113        2272 :             return std::make_unique<FE<0,L2_HIERARCHIC>>(fet);
     114             : 
     115           0 :           case L2_HIERARCHIC_VEC:
     116           0 :             return std::make_unique<FE<0,L2_HIERARCHIC_VEC>>(fet);
     117             : 
     118        1680 :           case SIDE_HIERARCHIC:
     119        1680 :             return std::make_unique<FE<0,SIDE_HIERARCHIC>>(fet);
     120             : 
     121        6864 :           case MONOMIAL:
     122        6864 :             return std::make_unique<FE<0,MONOMIAL>>(fet);
     123             : 
     124           0 :           case MONOMIAL_VEC:
     125           0 :             return std::make_unique<FE<0,MONOMIAL_VEC>>(fet);
     126             : 
     127             : #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
     128           0 :           case SZABAB:
     129           0 :             return std::make_unique<FE<0,SZABAB>>(fet);
     130             : 
     131           0 :           case BERNSTEIN:
     132           0 :             return std::make_unique<FE<0,BERNSTEIN>>(fet);
     133             : 
     134       22496 :           case RATIONAL_BERNSTEIN:
     135       22496 :             return std::make_unique<FE<0,RATIONAL_BERNSTEIN>>(fet);
     136             : #endif
     137             : 
     138           0 :           case XYZ:
     139           0 :             return std::make_unique<FEXYZ<0>>(fet);
     140             : 
     141        7976 :           case SCALAR:
     142        7976 :             return std::make_unique<FEScalar<0>>(fet);
     143             : 
     144           0 :           case NEDELEC_ONE:
     145           0 :             return std::make_unique<FENedelecOne<0>>(fet);
     146             : 
     147        5680 :           case RAVIART_THOMAS:
     148        5680 :             return std::make_unique<FERaviartThomas<0>>(fet);
     149             : 
     150           0 :           case L2_RAVIART_THOMAS:
     151           0 :             return std::make_unique<FEL2RaviartThomas<0>>(fet);
     152             : 
     153           0 :           case SUBDIVISION:
     154           0 :             return std::make_unique<FESubdivision>(fet);
     155             : 
     156           0 :           default:
     157           0 :             libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
     158             :           }
     159             :       }
     160             :       // 1D
     161     1042960 :     case 1:
     162             :       {
     163     1042960 :         switch (fet.family)
     164             :           {
     165           0 :           case CLOUGH:
     166           0 :             return std::make_unique<FE<1,CLOUGH>>(fet);
     167             : 
     168      274348 :           case HERMITE:
     169      274348 :             return std::make_unique<FE<1,HERMITE>>(fet);
     170             : 
     171      116712 :           case LAGRANGE:
     172      116712 :             return std::make_unique<FE<1,LAGRANGE>>(fet);
     173             : 
     174           0 :           case LAGRANGE_VEC:
     175           0 :             return std::make_unique<FE<1,LAGRANGE_VEC>>(fet);
     176             : 
     177       39636 :           case L2_LAGRANGE:
     178       39636 :             return std::make_unique<FE<1,L2_LAGRANGE>>(fet);
     179             : 
     180           0 :           case L2_LAGRANGE_VEC:
     181           0 :             return std::make_unique<FE<1,L2_LAGRANGE_VEC>>(fet);
     182             : 
     183           0 :           case HIERARCHIC_VEC:
     184           0 :             return std::make_unique<FE<1,HIERARCHIC_VEC>>(fet);
     185             : 
     186      212472 :           case HIERARCHIC:
     187      212472 :             return std::make_unique<FE<1,HIERARCHIC>>(fet);
     188             : 
     189       66060 :           case L2_HIERARCHIC:
     190       66060 :             return std::make_unique<FE<1,L2_HIERARCHIC>>(fet);
     191             : 
     192           0 :           case L2_HIERARCHIC_VEC:
     193           0 :             return std::make_unique<FE<1,L2_HIERARCHIC_VEC>>(fet);
     194             : 
     195       49236 :           case SIDE_HIERARCHIC:
     196       49236 :             return std::make_unique<FE<1,SIDE_HIERARCHIC>>(fet);
     197             : 
     198       98448 :           case MONOMIAL:
     199       98448 :             return std::make_unique<FE<1,MONOMIAL>>(fet);
     200             : 
     201           0 :           case MONOMIAL_VEC:
     202           0 :             return std::make_unique<FE<1,MONOMIAL_VEC>>(fet);
     203             : 
     204             : #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
     205       53280 :           case SZABAB:
     206       53280 :             return std::make_unique<FE<1,SZABAB>>(fet);
     207             : 
     208       53280 :           case BERNSTEIN:
     209       53280 :             return std::make_unique<FE<1,BERNSTEIN>>(fet);
     210             : 
     211       26640 :           case RATIONAL_BERNSTEIN:
     212       26640 :             return std::make_unique<FE<1,RATIONAL_BERNSTEIN>>(fet);
     213             : #endif
     214             : 
     215       52848 :           case XYZ:
     216       52848 :             return std::make_unique<FEXYZ<1>>(fet);
     217             : 
     218           0 :           case SCALAR:
     219           0 :             return std::make_unique<FEScalar<1>>(fet);
     220             : 
     221           0 :           case NEDELEC_ONE:
     222           0 :             return std::make_unique<FENedelecOne<1>>(fet);
     223             : 
     224           0 :           case RAVIART_THOMAS:
     225           0 :             return std::make_unique<FERaviartThomas<1>>(fet);
     226             : 
     227           0 :           case L2_RAVIART_THOMAS:
     228           0 :             return std::make_unique<FEL2RaviartThomas<1>>(fet);
     229             : 
     230           0 :           case SUBDIVISION:
     231           0 :             return std::make_unique<FESubdivision>(fet);
     232             : 
     233           0 :           default:
     234           0 :             libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
     235             :           }
     236             :       }
     237             : 
     238             : 
     239             :       // 2D
     240     5196843 :     case 2:
     241             :       {
     242     5196843 :         switch (fet.family)
     243             :           {
     244      124588 :           case CLOUGH:
     245      124588 :             return std::make_unique<FE<2,CLOUGH>>(fet);
     246             : 
     247      111548 :           case HERMITE:
     248      111548 :             return std::make_unique<FE<2,HERMITE>>(fet);
     249             : 
     250     2987867 :           case LAGRANGE:
     251     2987867 :             return std::make_unique<FE<2,LAGRANGE>>(fet);
     252             : 
     253      125280 :           case LAGRANGE_VEC:
     254      125280 :             return std::make_unique<FE<2,LAGRANGE_VEC>>(fet);
     255             : 
     256      142296 :           case L2_LAGRANGE:
     257      142296 :             return std::make_unique<FE<2,L2_LAGRANGE>>(fet);
     258             : 
     259        8472 :           case L2_LAGRANGE_VEC:
     260        8472 :             return std::make_unique<FE<2,L2_LAGRANGE_VEC>>(fet);
     261             : 
     262           0 :           case HIERARCHIC_VEC:
     263           0 :             return std::make_unique<FE<2,HIERARCHIC_VEC>>(fet);
     264             : 
     265      359636 :           case HIERARCHIC:
     266      359636 :             return std::make_unique<FE<2,HIERARCHIC>>(fet);
     267             : 
     268      189932 :           case L2_HIERARCHIC:
     269      189932 :             return std::make_unique<FE<2,L2_HIERARCHIC>>(fet);
     270             : 
     271        6816 :           case L2_HIERARCHIC_VEC:
     272        6816 :             return std::make_unique<FE<2,L2_HIERARCHIC_VEC>>(fet);
     273             : 
     274      179456 :           case SIDE_HIERARCHIC:
     275      179456 :             return std::make_unique<FE<2,SIDE_HIERARCHIC>>(fet);
     276             : 
     277      353164 :           case MONOMIAL:
     278      353164 :             return std::make_unique<FE<2,MONOMIAL>>(fet);
     279             : 
     280        3408 :           case MONOMIAL_VEC:
     281        3408 :             return std::make_unique<FE<2,MONOMIAL_VEC>>(fet);
     282             : 
     283             : #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
     284      151976 :           case SZABAB:
     285      151976 :             return std::make_unique<FE<2,SZABAB>>(fet);
     286             : 
     287      148896 :           case BERNSTEIN:
     288      148896 :             return std::make_unique<FE<2,BERNSTEIN>>(fet);
     289             : 
     290       59440 :           case RATIONAL_BERNSTEIN:
     291       59440 :             return std::make_unique<FE<2,RATIONAL_BERNSTEIN>>(fet);
     292             : #endif
     293             : 
     294      214800 :           case XYZ:
     295      214800 :             return std::make_unique<FEXYZ<2>>(fet);
     296             : 
     297        6840 :           case SCALAR:
     298        6840 :             return std::make_unique<FEScalar<2>>(fet);
     299             : 
     300        7668 :           case NEDELEC_ONE:
     301        7668 :             return std::make_unique<FENedelecOne<2>>(fet);
     302             : 
     303       11360 :           case RAVIART_THOMAS:
     304       11360 :             return std::make_unique<FERaviartThomas<2>>(fet);
     305             : 
     306        3400 :           case L2_RAVIART_THOMAS:
     307        3400 :             return std::make_unique<FEL2RaviartThomas<2>>(fet);
     308             : 
     309           0 :           case SUBDIVISION:
     310           0 :             return std::make_unique<FESubdivision>(fet);
     311             : 
     312           0 :           default:
     313           0 :             libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
     314             :           }
     315             :       }
     316             : 
     317             : 
     318             :       // 3D
     319     3608702 :     case 3:
     320             :       {
     321     3608702 :         switch (fet.family)
     322             :           {
     323           0 :           case CLOUGH:
     324           0 :             libmesh_error_msg("ERROR: Clough-Tocher elements currently only support 1D and 2D");
     325             : 
     326       19980 :           case HERMITE:
     327       19980 :             return std::make_unique<FE<3,HERMITE>>(fet);
     328             : 
     329      737242 :           case LAGRANGE:
     330      737242 :             return std::make_unique<FE<3,LAGRANGE>>(fet);
     331             : 
     332      190596 :           case LAGRANGE_VEC:
     333      190596 :             return std::make_unique<FE<3,LAGRANGE_VEC>>(fet);
     334             : 
     335      293110 :           case L2_LAGRANGE:
     336      293110 :             return std::make_unique<FE<3,L2_LAGRANGE>>(fet);
     337             : 
     338        5112 :           case L2_LAGRANGE_VEC:
     339        5112 :             return std::make_unique<FE<3,L2_LAGRANGE_VEC>>(fet);
     340             : 
     341           0 :           case HIERARCHIC_VEC:
     342           0 :             return std::make_unique<FE<3,HIERARCHIC_VEC>>(fet);
     343             : 
     344      401538 :           case HIERARCHIC:
     345      401538 :             return std::make_unique<FE<3,HIERARCHIC>>(fet);
     346             : 
     347      398388 :           case L2_HIERARCHIC:
     348      398388 :             return std::make_unique<FE<3,L2_HIERARCHIC>>(fet);
     349             : 
     350        2556 :           case L2_HIERARCHIC_VEC:
     351        2556 :             return std::make_unique<FE<3,L2_HIERARCHIC_VEC>>(fet);
     352             : 
     353      250428 :           case SIDE_HIERARCHIC:
     354      250428 :             return std::make_unique<FE<3,SIDE_HIERARCHIC>>(fet);
     355             : 
     356      622182 :           case MONOMIAL:
     357      622182 :             return std::make_unique<FE<3,MONOMIAL>>(fet);
     358             : 
     359           0 :           case MONOMIAL_VEC:
     360           0 :             return std::make_unique<FE<3,MONOMIAL_VEC>>(fet);
     361             : 
     362             : #ifdef LIBMESH_ENABLE_HIGHER_ORDER_SHAPES
     363           0 :           case SZABAB:
     364           0 :             return std::make_unique<FE<3,SZABAB>>(fet);
     365             : 
     366      142938 :           case BERNSTEIN:
     367      142938 :             return std::make_unique<FE<3,BERNSTEIN>>(fet);
     368             : 
     369       65598 :           case RATIONAL_BERNSTEIN:
     370       65598 :             return std::make_unique<FE<3,RATIONAL_BERNSTEIN>>(fet);
     371             : #endif
     372             : 
     373      464166 :           case XYZ:
     374      464166 :             return std::make_unique<FEXYZ<3>>(fet);
     375             : 
     376        1704 :           case SCALAR:
     377        1704 :             return std::make_unique<FEScalar<3>>(fet);
     378             : 
     379        6354 :           case NEDELEC_ONE:
     380        6354 :             return std::make_unique<FENedelecOne<3>>(fet);
     381             : 
     382        4260 :           case RAVIART_THOMAS:
     383        4260 :             return std::make_unique<FERaviartThomas<3>>(fet);
     384             : 
     385        2550 :           case L2_RAVIART_THOMAS:
     386        2550 :             return std::make_unique<FEL2RaviartThomas<3>>(fet);
     387             : 
     388           0 :           default:
     389           0 :             libmesh_error_msg("ERROR: Bad FEType.family= " << Utility::enum_to_string(fet.family));
     390             :           }
     391             :       }
     392             : 
     393           0 :     default:
     394           0 :       libmesh_error_msg("Invalid dimension dim = " << dim);
     395             :     }
     396             : }
     397             : 
     398             : 
     399             : 
     400    32725964 : void FEAbstract::get_refspace_nodes(const ElemType itemType, std::vector<Point> & nodes)
     401             : {
     402    32725964 :   const unsigned int n_nodes = Elem::type_to_n_nodes_map[itemType];
     403    32725964 :   if (n_nodes == invalid_uint)
     404           0 :     libmesh_error_msg("Number of nodes is not well-defined for " <<
     405             :                       Utility::enum_to_string(itemType));
     406             : 
     407    32725964 :   nodes.resize(n_nodes);
     408    32725964 :   switch(itemType)
     409             :     {
     410       28512 :     case NODEELEM:
     411             :       {
     412      114048 :         nodes[0] = Point (0.,0.,0.);
     413      114048 :         return;
     414             :       }
     415        6633 :     case EDGE3:
     416             :       {
     417       79490 :         nodes[2] = Point (0.,0.,0.);
     418             :         libmesh_fallthrough();
     419             :       }
     420     6995696 :     case EDGE2:
     421             :       {
     422     6995696 :         nodes[0] = Point (-1.,0.,0.);
     423     6995696 :         nodes[1] = Point (1.,0.,0.);
     424     6995696 :         return;
     425             :       }
     426           0 :     case EDGE4: // not nested with EDGE3
     427             :       {
     428           0 :         nodes[0] = Point (-1.,0.,0.);
     429           0 :         nodes[1] = Point (1.,0.,0.);
     430           0 :         nodes[2] = Point (-1./3.,0.,0.);
     431           0 :         nodes[3] - Point (1./3.,0.,0.);
     432           0 :         return;
     433             :       }
     434      125401 :     case TRI7:
     435             :       {
     436     1505848 :         nodes[6] = Point (1./3.,1./3.,0.);
     437             :         libmesh_fallthrough();
     438             :       }
     439     5382258 :     case TRI6:
     440             :       {
     441     5382258 :         nodes[3] = Point (.5,0.,0.);
     442     5382258 :         nodes[4] = Point (.5,.5,0.);
     443     5382258 :         nodes[5] = Point (0.,.5,0.);
     444             :         libmesh_fallthrough();
     445             :       }
     446     7719048 :     case TRI3:
     447             :     case TRISHELL3:
     448             :       {
     449     7719048 :         nodes[0] = Point (0.,0.,0.);
     450     7719048 :         nodes[1] = Point (1.,0.,0.);
     451     7719048 :         nodes[2] = Point (0.,1.,0.);
     452     7719048 :         return;
     453             :       }
     454      123066 :     case QUAD9:
     455             :     case QUADSHELL9:
     456             :       {
     457     1245501 :         nodes[8] = Point (0.,0.,0.);
     458             :         libmesh_fallthrough();
     459             :       }
     460     1372386 :     case QUAD8:
     461             :     case QUADSHELL8:
     462             :       {
     463     1372386 :         nodes[4] = Point (0.,-1.,0.);
     464     1372386 :         nodes[5] = Point (1.,0.,0.);
     465     1372386 :         nodes[6] = Point (0.,1.,0.);
     466     1372386 :         nodes[7] = Point (-1.,0.,0.);
     467             :         libmesh_fallthrough();
     468             :       }
     469     4048830 :     case QUAD4:
     470             :     case QUADSHELL4:
     471             :       {
     472     4048830 :         nodes[0] = Point (-1.,-1.,0.);
     473     4048830 :         nodes[1] = Point (1.,-1.,0.);
     474     4048830 :         nodes[2] = Point (1.,1.,0.);
     475     4048830 :         nodes[3] = Point (-1.,1.,0.);
     476     4048830 :         return;
     477             :       }
     478     1002574 :     case TET14:
     479             :       {
     480    12047874 :         nodes[10] = Point (1/Real(3),1/Real(3),0.);
     481    12047874 :         nodes[11] = Point (1/Real(3),0.,1/Real(3));
     482    12047874 :         nodes[12] = Point (1/Real(3),1/Real(3),1/Real(3));
     483    12047874 :         nodes[13] = Point (0.,1/Real(3),1/Real(3));
     484             :         libmesh_fallthrough();
     485             :       }
     486    12100962 :     case TET10:
     487             :       {
     488    12100962 :         nodes[4] = Point (.5,0.,0.);
     489    12100962 :         nodes[5] = Point (.5,.5,0.);
     490    12100962 :         nodes[6] = Point (0.,.5,0.);
     491    12100962 :         nodes[7] = Point (0.,0.,.5);
     492    12100962 :         nodes[8] = Point (.5,0.,.5);
     493    12100962 :         nodes[9] = Point (0.,.5,.5);
     494             :         libmesh_fallthrough();
     495             :       }
     496    12102546 :     case TET4:
     497             :       {
     498    12102546 :         nodes[0] = Point (0.,0.,0.);
     499    12102546 :         nodes[1] = Point (1.,0.,0.);
     500    12102546 :         nodes[2] = Point (0.,1.,0.);
     501    12102546 :         nodes[3] = Point (0.,0.,1.);
     502    12102546 :         return;
     503             :       }
     504       39513 :     case HEX27:
     505             :       {
     506      488692 :         nodes[20] = Point (0.,0.,-1.);
     507      488692 :         nodes[21] = Point (0.,-1.,0.);
     508      488692 :         nodes[22] = Point (1.,0.,0.);
     509      488692 :         nodes[23] = Point (0.,1.,0.);
     510      488692 :         nodes[24] = Point (-1.,0.,0.);
     511      488692 :         nodes[25] = Point (0.,0.,1.);
     512      488692 :         nodes[26] = Point (0.,0.,0.);
     513             :         libmesh_fallthrough();
     514             :       }
     515      493876 :     case HEX20:
     516             :       {
     517      493876 :         nodes[8] = Point (0.,-1.,-1.);
     518      493876 :         nodes[9] = Point (1.,0.,-1.);
     519      493876 :         nodes[10] = Point (0.,1.,-1.);
     520      493876 :         nodes[11] = Point (-1.,0.,-1.);
     521      493876 :         nodes[12] = Point (-1.,-1.,0.);
     522      493876 :         nodes[13] = Point (1.,-1.,0.);
     523      493876 :         nodes[14] = Point (1.,1.,0.);
     524      493876 :         nodes[15] = Point (-1.,1.,0.);
     525      493876 :         nodes[16] = Point (0.,-1.,1.);
     526      493876 :         nodes[17] = Point (1.,0.,1.);
     527      493876 :         nodes[18] = Point (0.,1.,1.);
     528      493876 :         nodes[19] = Point (-1.,0.,1.);
     529             :         libmesh_fallthrough();
     530             :       }
     531     1532622 :     case HEX8:
     532             :       {
     533     1532622 :         nodes[0] = Point (-1.,-1.,-1.);
     534     1532622 :         nodes[1] = Point (1.,-1.,-1.);
     535     1532622 :         nodes[2] = Point (1.,1.,-1.);
     536     1532622 :         nodes[3] = Point (-1.,1.,-1.);
     537     1532622 :         nodes[4] = Point (-1.,-1.,1.);
     538     1532622 :         nodes[5] = Point (1.,-1.,1.);
     539     1532622 :         nodes[6] = Point (1.,1.,1.);
     540     1532622 :         nodes[7] = Point (-1.,1.,1.);
     541     1532622 :         return;
     542             :       }
     543        7604 :     case PRISM21:
     544             :       {
     545       93003 :         nodes[20] = Point (1/Real(3),1/Real(3),0);
     546             :         libmesh_fallthrough();
     547             :       }
     548      145855 :     case PRISM20:
     549             :       {
     550      145855 :         nodes[18] = Point (1/Real(3),1/Real(3),-1);
     551      145855 :         nodes[19] = Point (1/Real(3),1/Real(3),1);
     552             :         libmesh_fallthrough();
     553             :       }
     554      188154 :     case PRISM18:
     555             :       {
     556      188154 :         nodes[15] = Point (.5,0.,0.);
     557      188154 :         nodes[16] = Point (.5,.5,0.);
     558      188154 :         nodes[17] = Point (0.,.5,0.);
     559             :         libmesh_fallthrough();
     560             :       }
     561      188154 :     case PRISM15:
     562             :       {
     563      188154 :         nodes[6] = Point (.5,0.,-1.);
     564      188154 :         nodes[7] = Point (.5,.5,-1.);
     565      188154 :         nodes[8] = Point (0.,.5,-1.);
     566      188154 :         nodes[9] = Point (0.,0.,0.);
     567      188154 :         nodes[10] = Point (1.,0.,0.);
     568      188154 :         nodes[11] = Point (0.,1.,0.);
     569      188154 :         nodes[12] = Point (.5,0.,1.);
     570      188154 :         nodes[13] = Point (.5,.5,1.);
     571      188154 :         nodes[14] = Point (0.,.5,1.);
     572             :         libmesh_fallthrough();
     573             :       }
     574      213174 :     case PRISM6:
     575             :       {
     576      213174 :         nodes[0] = Point (0.,0.,-1.);
     577      213174 :         nodes[1] = Point (1.,0.,-1.);
     578      213174 :         nodes[2] = Point (0.,1.,-1.);
     579      213174 :         nodes[3] = Point (0.,0.,1.);
     580      213174 :         nodes[4] = Point (1.,0.,1.);
     581      213174 :         nodes[5] = Point (0.,1.,1.);
     582      213174 :         return;
     583             :       }
     584           0 :     case PYRAMID18:
     585             :       {
     586             :         // triangle centers
     587           0 :         nodes[14] = Point (-2/Real(3),0.,1/Real(3));
     588           0 :         nodes[15] = Point (0.,2/Real(3),1/Real(3));
     589           0 :         nodes[16] = Point (2/Real(3),0.,1/Real(3));
     590           0 :         nodes[17] = Point (0.,-2/Real(3),1/Real(3));
     591             : 
     592             :         libmesh_fallthrough();
     593             :       }
     594           0 :     case PYRAMID14:
     595             :       {
     596             :         // base center
     597           0 :         nodes[13] = Point (0.,0.,0.);
     598             : 
     599             :         libmesh_fallthrough();
     600             :       }
     601           0 :     case PYRAMID13:
     602             :       {
     603             :         // base midedge
     604           0 :         nodes[5] = Point (0.,-1.,0.);
     605           0 :         nodes[6] = Point (1.,0.,0.);
     606           0 :         nodes[7] = Point (0.,1.,0.);
     607           0 :         nodes[8] = Point (-1,0.,0.);
     608             : 
     609             :         // lateral midedge
     610           0 :         nodes[9] = Point (-.5,-.5,.5);
     611           0 :         nodes[10] = Point (.5,-.5,.5);
     612           0 :         nodes[11] = Point (.5,.5,.5);
     613           0 :         nodes[12] = Point (-.5,.5,.5);
     614             : 
     615             :         libmesh_fallthrough();
     616             :       }
     617           0 :     case PYRAMID5:
     618             :       {
     619             :         // base corners
     620           0 :         nodes[0] = Point (-1.,-1.,0.);
     621           0 :         nodes[1] = Point (1.,-1.,0.);
     622           0 :         nodes[2] = Point (1.,1.,0.);
     623           0 :         nodes[3] = Point (-1.,1.,0.);
     624             :         // apex
     625           0 :         nodes[4] = Point (0.,0.,1.);
     626           0 :         return;
     627             :       }
     628             : 
     629           0 :     default:
     630           0 :       libmesh_error_msg("ERROR: Unknown element type " << Utility::enum_to_string(itemType));
     631             :     }
     632             : }
     633             : 
     634             : 
     635             : 
     636             : #ifdef LIBMESH_ENABLE_DEPRECATED
     637           0 : bool FEAbstract::on_reference_element(const Point & p, const ElemType t, const Real eps)
     638             : {
     639             :   // Use Elem::on_reference_element() instead
     640             :   libmesh_deprecated();
     641             : 
     642           0 :   libmesh_assert_greater_equal (eps, 0.);
     643             : 
     644           0 :   const Real xi   = p(0);
     645             : #if LIBMESH_DIM > 1
     646           0 :   const Real eta  = p(1);
     647             : #else
     648             :   const Real eta  = 0.;
     649             : #endif
     650             : #if LIBMESH_DIM > 2
     651           0 :   const Real zeta = p(2);
     652             : #else
     653             :   const Real zeta  = 0.;
     654             : #endif
     655             : 
     656           0 :   switch (t)
     657             :     {
     658           0 :     case NODEELEM:
     659             :       {
     660           0 :         return (!xi && !eta && !zeta);
     661             :       }
     662           0 :     case EDGE2:
     663             :     case EDGE3:
     664             :     case EDGE4:
     665             :       {
     666             :         // The reference 1D element is [-1,1].
     667           0 :         if ((xi >= -1.-eps) &&
     668           0 :             (xi <=  1.+eps))
     669           0 :           return true;
     670             : 
     671           0 :         return false;
     672             :       }
     673             : 
     674             : 
     675           0 :     case TRI3:
     676             :     case TRISHELL3:
     677             :     case TRI6:
     678             :     case TRI7:
     679             :       {
     680             :         // The reference triangle is isosceles
     681             :         // and is bound by xi=0, eta=0, and xi+eta=1.
     682           0 :         if ((xi  >= 0.-eps) &&
     683           0 :             (eta >= 0.-eps) &&
     684           0 :             ((xi + eta) <= 1.+eps))
     685           0 :           return true;
     686             : 
     687           0 :         return false;
     688             :       }
     689             : 
     690             : 
     691           0 :     case QUAD4:
     692             :     case QUADSHELL4:
     693             :     case QUAD8:
     694             :     case QUADSHELL8:
     695             :     case QUAD9:
     696             :     case QUADSHELL9:
     697             :       {
     698             :         // The reference quadrilateral element is [-1,1]^2.
     699           0 :         if ((xi  >= -1.-eps) &&
     700           0 :             (xi  <=  1.+eps) &&
     701           0 :             (eta >= -1.-eps) &&
     702           0 :             (eta <=  1.+eps))
     703           0 :           return true;
     704             : 
     705           0 :         return false;
     706             :       }
     707             : 
     708             : 
     709           0 :     case TET4:
     710             :     case TET10:
     711             :     case TET14:
     712             :       {
     713             :         // The reference tetrahedral is isosceles
     714             :         // and is bound by xi=0, eta=0, zeta=0,
     715             :         // and xi+eta+zeta=1.
     716           0 :         if ((xi   >= 0.-eps) &&
     717           0 :             (eta  >= 0.-eps) &&
     718           0 :             (zeta >= 0.-eps) &&
     719           0 :             ((xi + eta + zeta) <= 1.+eps))
     720           0 :           return true;
     721             : 
     722           0 :         return false;
     723             :       }
     724             : 
     725             : 
     726           0 :     case HEX8:
     727             :     case HEX20:
     728             :     case HEX27:
     729             :       {
     730             :         /*
     731             :           if ((xi   >= -1.) &&
     732             :           (xi   <=  1.) &&
     733             :           (eta  >= -1.) &&
     734             :           (eta  <=  1.) &&
     735             :           (zeta >= -1.) &&
     736             :           (zeta <=  1.))
     737             :           return true;
     738             :         */
     739             : 
     740             :         // The reference hexahedral element is [-1,1]^3.
     741           0 :         if ((xi   >= -1.-eps) &&
     742           0 :             (xi   <=  1.+eps) &&
     743           0 :             (eta  >= -1.-eps) &&
     744           0 :             (eta  <=  1.+eps) &&
     745           0 :             (zeta >= -1.-eps) &&
     746           0 :             (zeta <=  1.+eps))
     747             :           {
     748             :             //    libMesh::out << "Strange Point:\n";
     749             :             //    p.print();
     750           0 :             return true;
     751             :           }
     752             : 
     753           0 :         return false;
     754             :       }
     755             : 
     756           0 :     case PRISM6:
     757             :     case PRISM15:
     758             :     case PRISM18:
     759             :     case PRISM20:
     760             :     case PRISM21:
     761             :       {
     762             :         // Figure this one out...
     763             :         // inside the reference triangle with zeta in [-1,1]
     764           0 :         if ((xi   >=  0.-eps) &&
     765           0 :             (eta  >=  0.-eps) &&
     766           0 :             (zeta >= -1.-eps) &&
     767           0 :             (zeta <=  1.+eps) &&
     768           0 :             ((xi + eta) <= 1.+eps))
     769           0 :           return true;
     770             : 
     771           0 :         return false;
     772             :       }
     773             : 
     774             : 
     775           0 :     case PYRAMID5:
     776             :     case PYRAMID13:
     777             :     case PYRAMID14:
     778             :     case PYRAMID18:
     779             :       {
     780             :         // Check that the point is on the same side of all the faces
     781             :         // by testing whether:
     782             :         //
     783             :         // n_i.(x - x_i) <= 0
     784             :         //
     785             :         // for each i, where:
     786             :         //   n_i is the outward normal of face i,
     787             :         //   x_i is a point on face i.
     788           0 :         if ((-eta - 1. + zeta <= 0.+eps) &&
     789           0 :             (  xi - 1. + zeta <= 0.+eps) &&
     790           0 :             ( eta - 1. + zeta <= 0.+eps) &&
     791           0 :             ( -xi - 1. + zeta <= 0.+eps) &&
     792           0 :             (            zeta >= 0.-eps))
     793           0 :           return true;
     794             : 
     795           0 :         return false;
     796             :       }
     797             : 
     798             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
     799           0 :     case INFHEX8:
     800             :     case INFHEX16:
     801             :     case INFHEX18:
     802             :       {
     803             :         // The reference infhex8 is a [-1,1]^3.
     804           0 :         if ((xi   >= -1.-eps) &&
     805           0 :             (xi   <=  1.+eps) &&
     806           0 :             (eta  >= -1.-eps) &&
     807           0 :             (eta  <=  1.+eps) &&
     808           0 :             (zeta >= -1.-eps) &&
     809           0 :             (zeta <=  1.+eps))
     810             :           {
     811           0 :             return true;
     812             :           }
     813           0 :         return false;
     814             :       }
     815             : 
     816           0 :     case INFPRISM6:
     817             :     case INFPRISM12:
     818             :       {
     819             :         // inside the reference triangle with zeta in [-1,1]
     820           0 :         if ((xi   >=  0.-eps) &&
     821           0 :             (eta  >=  0.-eps) &&
     822           0 :             (zeta >= -1.-eps) &&
     823           0 :             (zeta <=  1.+eps) &&
     824           0 :             ((xi + eta) <= 1.+eps))
     825             :           {
     826           0 :             return true;
     827             :           }
     828             : 
     829           0 :         return false;
     830             :       }
     831             : #endif
     832             : 
     833           0 :     default:
     834           0 :       libmesh_error_msg("ERROR: Unknown element type " << Utility::enum_to_string(t));
     835             :     }
     836             : 
     837             :   // If we get here then the point is _not_ in the
     838             :   // reference element.   Better return false.
     839             : 
     840             :   return false;
     841             : }
     842             : #endif // LIBMESH_ENABLE_DEPRECATED
     843             : 
     844             : 
     845             : 
     846           0 : void FEAbstract::print_JxW(std::ostream & os) const
     847             : {
     848           0 :   this->_fe_map->print_JxW(os);
     849           0 : }
     850             : 
     851             : 
     852             : 
     853           0 : void FEAbstract::print_xyz(std::ostream & os) const
     854             : {
     855           0 :   this->_fe_map->print_xyz(os);
     856           0 : }
     857             : 
     858             : 
     859           0 : void FEAbstract::print_info(std::ostream & os) const
     860             : {
     861           0 :   os << "phi[i][j]: Shape function i at quadrature pt. j" << std::endl;
     862           0 :   this->print_phi(os);
     863             : 
     864           0 :   os << "dphi[i][j]: Shape function i's gradient at quadrature pt. j" << std::endl;
     865           0 :   this->print_dphi(os);
     866             : 
     867           0 :   os << "XYZ locations of the quadrature pts." << std::endl;
     868           0 :   this->print_xyz(os);
     869             : 
     870           0 :   os << "Values of JxW at the quadrature pts." << std::endl;
     871           0 :   this->print_JxW(os);
     872           0 : }
     873             : 
     874             : 
     875           0 : std::ostream & operator << (std::ostream & os, const FEAbstract & fe)
     876             : {
     877           0 :   fe.print_info(os);
     878           0 :   return os;
     879             : }
     880             : 
     881             : 
     882             : 
     883             : #ifdef LIBMESH_ENABLE_AMR
     884             : 
     885             : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
     886      953952 : void FEAbstract::compute_node_constraints (NodeConstraints & constraints,
     887             :                                            const Elem * elem)
     888             : {
     889      476975 :   libmesh_assert(elem);
     890             : 
     891      953952 :   const unsigned int Dim = elem->dim();
     892             : 
     893             :   // Only constrain elements in 2,3D.
     894      953952 :   if (Dim == 1)
     895       85098 :     return;
     896             : 
     897             :   // Only constrain active and ancestor elements
     898      939614 :   if (elem->subactive())
     899       34324 :     return;
     900             : 
     901             : 
     902             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
     903      870966 :   if (elem->infinite())
     904             :     {
     905        2112 :       const FEType fe_t(elem->default_order(), FEMap::map_fe_type(*elem));
     906             : 
     907             :       // expand the infinite_compute_constraint in its template-arguments.
     908        2112 :       switch(Dim)
     909             :       {
     910           0 :          case 2:
     911             :             {
     912           0 :             inf_fe_family_mapping_switch(2, inf_compute_node_constraints (constraints, elem) , ,; break;);
     913           0 :             break;
     914             :           }
     915        1056 :          case 3:
     916             :             {
     917        2112 :             inf_fe_family_mapping_switch(3, inf_compute_node_constraints (constraints, elem) , ,; break;);
     918        1056 :             break;
     919             :             }
     920           0 :          default:
     921           0 :            libmesh_error_msg("Invalid dim = " << Dim);
     922             :       }
     923        1056 :       return;
     924             :     }
     925             : 
     926             : #endif
     927      868854 :   const FEFamily mapping_family = FEMap::map_fe_type(*elem);
     928      868854 :   const FEType fe_type(elem->default_side_order(), mapping_family);
     929             : 
     930             :   // Pull objects out of the loop to reduce heap operations
     931      868854 :   std::vector<const Node *> my_nodes, parent_nodes;
     932      868854 :   std::unique_ptr<const Elem> my_side, parent_side;
     933             : 
     934             :   // Look at the element faces.  Check to see if we need to
     935             :   // build constraints.
     936     4360050 :   for (auto s : elem->side_index_range())
     937     6870566 :     if (elem->neighbor_ptr(s) != nullptr &&
     938     3267544 :         elem->neighbor_ptr(s) != remote_elem)
     939     3267544 :       if (elem->neighbor_ptr(s)->level() < elem->level()) // constrain dofs shared between
     940             :         {                                                 // this element and ones coarser
     941             :           // than this element.
     942             :           // Get pointers to the elements of interest and its parent.
     943       85584 :           const Elem * parent = elem->parent();
     944             : 
     945             :           // This can't happen...  Only level-0 elements have nullptr
     946             :           // parents, and no level-0 elements can be at a higher
     947             :           // level than their neighbors!
     948       42792 :           libmesh_assert(parent);
     949             : 
     950       85584 :           elem->build_side_ptr(my_side, s);
     951       85584 :           parent->build_side_ptr(parent_side, s);
     952             : 
     953       85584 :           const unsigned int n_side_nodes = my_side->n_nodes();
     954             : 
     955       42792 :           my_nodes.clear();
     956       85584 :           my_nodes.reserve (n_side_nodes);
     957       42792 :           parent_nodes.clear();
     958       85584 :           parent_nodes.reserve (n_side_nodes);
     959             : 
     960      311236 :           for (unsigned int n=0; n != n_side_nodes; ++n)
     961      338478 :             my_nodes.push_back(my_side->node_ptr(n));
     962             : 
     963      311236 :           for (unsigned int n=0; n != n_side_nodes; ++n)
     964      338478 :             parent_nodes.push_back(parent_side->node_ptr(n));
     965             : 
     966      268444 :           for (unsigned int my_side_n=0;
     967      311236 :                my_side_n < n_side_nodes;
     968             :                my_side_n++)
     969             :             {
     970             :               // We can have an FE type that supports an order
     971             :               // partially, such that sides do not support the same
     972             :               // order.  E.g. we say that a LAGRANGE PRISM21 supports
     973             :               // "third" order to distinguish its shape functions from
     974             :               // a PRISM18, but the QUAD9 sides will still only
     975             :               // support second order.
     976      225652 :               FEType side_fe_type = fe_type;
     977             :               const int side_max_order =
     978      225652 :                 FEInterface::max_order(fe_type, my_side->type());
     979             : 
     980      225652 :               if ((int)fe_type.order > side_max_order)
     981        2736 :                 side_fe_type.order = side_max_order;
     982             : 
     983             :               // Do not use the p_level(), if any, that is inherited by the side.
     984      112826 :               libmesh_assert_less
     985             :                 (my_side_n,
     986             :                  FEInterface::n_dofs(side_fe_type, /*extra_order=*/0,
     987             :                                      my_side.get()));
     988             : 
     989      225652 :               const Node * my_node = my_nodes[my_side_n];
     990             : 
     991             :               // The support point of the DOF
     992      225652 :               const Point & support_point = *my_node;
     993             : 
     994             :               // Figure out where my node lies on their reference element.
     995             :               const Point mapped_point = FEMap::inverse_map(Dim-1,
     996             :                                                             parent_side.get(),
     997      225652 :                                                             support_point);
     998             : 
     999             :               // Compute the parent's side shape function values.
    1000      819758 :               for (unsigned int their_side_n=0;
    1001      932584 :                    their_side_n < n_side_nodes;
    1002             :                    their_side_n++)
    1003             :                 {
    1004             :                   // Do not use the p_level(), if any, that is inherited by the side.
    1005      353466 :                   libmesh_assert_less
    1006             :                     (their_side_n,
    1007             :                      FEInterface::n_dofs(side_fe_type,
    1008             :                                          /*extra_order=*/0,
    1009             :                                          parent_side.get()));
    1010             : 
    1011     1060398 :                   const Node * their_node = parent_nodes[their_side_n];
    1012      353466 :                   libmesh_assert(their_node);
    1013             : 
    1014             :                   // Do not use the p_level(), if any, that is inherited by the side.
    1015      706932 :                   const Real their_value = FEInterface::shape(side_fe_type,
    1016             :                                                               /*extra_order=*/0,
    1017             :                                                               parent_side.get(),
    1018             :                                                               their_side_n,
    1019      706932 :                                                               mapped_point);
    1020             : 
    1021      353466 :                   const Real their_mag = std::abs(their_value);
    1022             : #ifdef DEBUG
    1023             :                   // Protect for the case u_i ~= u_j,
    1024             :                   // in which case i better equal j.
    1025      353466 :                   if (their_mag > 0.999)
    1026             :                     {
    1027       50058 :                       libmesh_assert_equal_to (my_node, their_node);
    1028       50058 :                       libmesh_assert_less (std::abs(their_value - 1.), 0.001);
    1029             :                     }
    1030             :                   else
    1031             : #endif
    1032             :                     // To make nodal constraints useful for constructing
    1033             :                     // sparsity patterns faster, we need to get EVERY
    1034             :                     // POSSIBLE constraint coupling identified, even if
    1035             :                     // there is no coupling in the isoparametric
    1036             :                     // Lagrange case.
    1037      656874 :                     if (their_mag < 1.e-5)
    1038             :                       {
    1039             :                         // since we may be running this method concurrently
    1040             :                         // on multiple threads we need to acquire a lock
    1041             :                         // before modifying the shared constraint_row object.
    1042      147434 :                         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1043             : 
    1044             :                         // A reference to the constraint row.
    1045      294868 :                         NodeConstraintRow & constraint_row = constraints[my_node].first;
    1046             : 
    1047      294868 :                         constraint_row.emplace(their_node, 0.);
    1048             :                       }
    1049             :                   // To get nodal coordinate constraints right, only
    1050             :                   // add non-zero and non-identity values for Lagrange
    1051             :                   // basis functions.
    1052             :                     else // (1.e-5 <= their_mag <= .999)
    1053             :                       {
    1054             :                         // since we may be running this method concurrently
    1055             :                         // on multiple threads we need to acquire a lock
    1056             :                         // before modifying the shared constraint_row object.
    1057      311948 :                         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1058             : 
    1059             :                         // A reference to the constraint row.
    1060      362006 :                         NodeConstraintRow & constraint_row = constraints[my_node].first;
    1061             : 
    1062      155974 :                         constraint_row.emplace(their_node, their_value);
    1063             :                       }
    1064             :                 }
    1065             :             }
    1066             :         }
    1067             : }
    1068             : 
    1069             : #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
    1070             : 
    1071             : #endif // #ifdef LIBMESH_ENABLE_AMR
    1072             : 
    1073             : 
    1074             : 
    1075             : #ifdef LIBMESH_ENABLE_PERIODIC
    1076             : 
    1077             : #ifdef LIBMESH_ENABLE_NODE_CONSTRAINTS
    1078      129724 : void FEAbstract::compute_periodic_node_constraints (NodeConstraints & constraints,
    1079             :                                                     const PeriodicBoundaries & boundaries,
    1080             :                                                     const MeshBase & mesh,
    1081             :                                                     const PointLocatorBase * point_locator,
    1082             :                                                     const Elem * elem)
    1083             : {
    1084             :   // Only bother if we truly have periodic boundaries
    1085      129724 :   if (boundaries.empty())
    1086       38982 :     return;
    1087             : 
    1088       64862 :   libmesh_assert(elem);
    1089             : 
    1090             :   // Only constrain active elements with this method
    1091       64862 :   if (!elem->active())
    1092       19491 :     return;
    1093             : 
    1094       90742 :   const unsigned int Dim = elem->dim();
    1095             : 
    1096       90742 :   const FEFamily mapping_family = FEMap::map_fe_type(*elem);
    1097       90742 :   const FEType fe_type(elem->default_side_order(), mapping_family);
    1098             : 
    1099             :   // Pull objects out of the loop to reduce heap operations
    1100       90742 :   std::vector<const Node *> my_nodes, neigh_nodes;
    1101       90742 :   std::unique_ptr<const Elem> my_side, neigh_side;
    1102             : 
    1103             :   // Look at the element faces.  Check to see if we need to
    1104             :   // build constraints.
    1105       90742 :   std::vector<boundary_id_type> bc_ids;
    1106      441726 :   for (auto s : elem->side_index_range())
    1107             :     {
    1108      526476 :       if (elem->neighbor_ptr(s))
    1109      172162 :         continue;
    1110             : 
    1111        6660 :       mesh.get_boundary_info().boundary_ids (elem, s, bc_ids);
    1112       12272 :       for (const auto & boundary_id : bc_ids)
    1113             :         {
    1114        5612 :           const PeriodicBoundaryBase * periodic = boundaries.boundary(boundary_id);
    1115        5612 :           if (periodic)
    1116             :             {
    1117        2644 :               libmesh_assert(point_locator);
    1118             : 
    1119             :               // Get pointers to the element's neighbor.
    1120             :               unsigned int s_neigh;
    1121        5288 :               const Elem * neigh = boundaries.neighbor(boundary_id, *point_locator, elem, s, &s_neigh);
    1122             : 
    1123        5288 :               libmesh_error_msg_if
    1124             :                 (!neigh, "PeriodicBoundaries can't find a periodic neighbor for element " <<
    1125             :                          elem->id() << " side " << s);
    1126             : 
    1127             :               // h refinement constraints:
    1128             :               // constrain dofs shared between
    1129             :               // this element and ones as coarse
    1130             :               // as or coarser than this element.
    1131        5288 :               if (neigh->level() <= elem->level())
    1132             :                 {
    1133             : #ifdef LIBMESH_ENABLE_AMR
    1134        2196 :                   libmesh_assert(neigh->active());
    1135             : #endif // #ifdef LIBMESH_ENABLE_AMR
    1136             : 
    1137        4392 :                   elem->build_side_ptr(my_side, s);
    1138        4392 :                   neigh->build_side_ptr(neigh_side, s_neigh);
    1139             : 
    1140        4392 :                   const unsigned int n_side_nodes = my_side->n_nodes();
    1141             : 
    1142        2196 :                   my_nodes.clear();
    1143        4392 :                   my_nodes.reserve (n_side_nodes);
    1144        2196 :                   neigh_nodes.clear();
    1145        4392 :                   neigh_nodes.reserve (n_side_nodes);
    1146             : 
    1147       14000 :                   for (unsigned int n=0; n != n_side_nodes; ++n)
    1148       14412 :                     my_nodes.push_back(my_side->node_ptr(n));
    1149             : 
    1150       14000 :                   for (unsigned int n=0; n != n_side_nodes; ++n)
    1151       14412 :                     neigh_nodes.push_back(neigh_side->node_ptr(n));
    1152             : 
    1153             :                   // Make sure we're not adding recursive constraints
    1154             :                   // due to the redundancy in the way we add periodic
    1155             :                   // boundary constraints, or adding constraints to
    1156             :                   // nodes that already have AMR constraints
    1157        6588 :                   std::vector<bool> skip_constraint(n_side_nodes, false);
    1158             : 
    1159       11804 :                   for (unsigned int my_side_n=0;
    1160       14000 :                        my_side_n < n_side_nodes;
    1161             :                        my_side_n++)
    1162             :                     {
    1163             :                       // Do not use the p_level(), if any, that is inherited by the side.
    1164        4804 :                       libmesh_assert_less (my_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, my_side.get()));
    1165             : 
    1166       14412 :                       const Node * my_node = my_nodes[my_side_n];
    1167             : 
    1168             :                       // If we've already got a constraint on this
    1169             :                       // node, then the periodic constraint is
    1170             :                       // redundant
    1171             :                       {
    1172        4804 :                         Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1173             : 
    1174        4804 :                         if (constraints.count(my_node))
    1175             :                           {
    1176        3933 :                             skip_constraint[my_side_n] = true;
    1177        1970 :                             continue;
    1178             :                           }
    1179             :                       }
    1180             : 
    1181             :                       // Compute the neighbors's side shape function values.
    1182       16402 :                       for (unsigned int their_side_n=0;
    1183       19243 :                            their_side_n < n_side_nodes;
    1184             :                            their_side_n++)
    1185             :                         {
    1186             :                           // Do not use the p_level(), if any, that is inherited by the side.
    1187        6777 :                           libmesh_assert_less (their_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, neigh_side.get()));
    1188             : 
    1189       20359 :                           const Node * their_node = neigh_nodes[their_side_n];
    1190             : 
    1191             :                           // If there's a constraint on an opposing node,
    1192             :                           // we need to see if it's constrained by
    1193             :                           // *our side* making any periodic constraint
    1194             :                           // on us recursive
    1195             :                           {
    1196        6777 :                             Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1197             : 
    1198        6777 :                             if (!constraints.count(their_node))
    1199        4134 :                               continue;
    1200             : 
    1201             :                             const NodeConstraintRow & their_constraint_row =
    1202        5294 :                               constraints[their_node].first;
    1203             : 
    1204       19569 :                             for (unsigned int orig_side_n=0;
    1205       22220 :                                  orig_side_n < n_side_nodes;
    1206             :                                  orig_side_n++)
    1207             :                               {
    1208             :                                 // Do not use the p_level(), if any, that is inherited by the side.
    1209        8455 :                                 libmesh_assert_less (orig_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, my_side.get()));
    1210             : 
    1211       25397 :                                 const Node * orig_node = my_nodes[orig_side_n];
    1212             : 
    1213        8455 :                                 if (their_constraint_row.count(orig_node))
    1214       10655 :                                   skip_constraint[orig_side_n] = true;
    1215             :                               }
    1216             :                           }
    1217             :                         }
    1218             :                     }
    1219       11804 :                   for (unsigned int my_side_n=0;
    1220       14000 :                        my_side_n < n_side_nodes;
    1221             :                        my_side_n++)
    1222             :                     {
    1223             :                       // Do not use the p_level(), if any, that is inherited by the side.
    1224        4804 :                       libmesh_assert_less (my_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, my_side.get()));
    1225             : 
    1226       14412 :                       if (skip_constraint[my_side_n])
    1227        5628 :                         continue;
    1228             : 
    1229        3980 :                       const Node * my_node = my_nodes[my_side_n];
    1230             : 
    1231             :                       // Figure out where my node lies on their reference element.
    1232        3980 :                       const Point neigh_point = periodic->get_corresponding_pos(*my_node);
    1233             : 
    1234             :                       // Figure out where my node lies on their reference element.
    1235             :                       const Point mapped_point =
    1236             :                         FEMap::inverse_map(Dim-1, neigh_side.get(),
    1237        3980 :                                            neigh_point);
    1238             : 
    1239       10508 :                       for (unsigned int their_side_n=0;
    1240       12500 :                            their_side_n < n_side_nodes;
    1241             :                            their_side_n++)
    1242             :                         {
    1243             :                           // Do not use the p_level(), if any, that is inherited by the side.
    1244        4256 :                           libmesh_assert_less (their_side_n, FEInterface::n_dofs(fe_type, /*extra_order=*/0, neigh_side.get()));
    1245             : 
    1246       12784 :                           const Node * their_node = neigh_nodes[their_side_n];
    1247        4256 :                           libmesh_assert(their_node);
    1248             : 
    1249             :                           // Do not use the p_level(), if any, that is inherited by the side.
    1250        8520 :                           const Real their_value = FEInterface::shape(fe_type,
    1251             :                                                                       /*extra_order=*/0,
    1252             :                                                                       neigh_side.get(),
    1253             :                                                                       their_side_n,
    1254        8520 :                                                                       mapped_point);
    1255             : 
    1256             :                           // since we may be running this method concurrently
    1257             :                           // on multiple threads we need to acquire a lock
    1258             :                           // before modifying the shared constraint_row object.
    1259             :                           {
    1260        8512 :                             Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1261             : 
    1262             :                             NodeConstraintRow & constraint_row =
    1263        8520 :                               constraints[my_node].first;
    1264             : 
    1265        4256 :                             constraint_row.emplace(their_node, their_value);
    1266             :                           }
    1267             :                         }
    1268             :                     }
    1269             :                 }
    1270             :             }
    1271             :         }
    1272             :     }
    1273             : }
    1274             : #endif // LIBMESH_ENABLE_NODE_CONSTRAINTS
    1275             : 
    1276             : #endif // LIBMESH_ENABLE_PERIODIC
    1277             : 
    1278             : 
    1279     1831237 : unsigned int FEAbstract::n_quadrature_points () const
    1280             : {
    1281      212706 :   if (this->shapes_on_quadrature)
    1282             :     {
    1283      212690 :       libmesh_assert(this->qrule);
    1284      212690 :       libmesh_assert_equal_to(this->qrule->n_points(),
    1285             :                               this->_n_total_qp);
    1286             :     }
    1287     1831237 :   return this->_n_total_qp;
    1288             : }
    1289             : 
    1290             : } // namespace libMesh

Generated by: LCOV version 1.14