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

Generated by: LCOV version 1.14