LCOV - code coverage report
Current view: top level - src/fe - fe_lagrange.C (source / functions) Hit Total Coverage
Test: libMesh/libmesh: #4583 (689827) with base 9e5b0b Lines: 402 544 73.9 %
Date: 2026-10-16 15:05:09 Functions: 47 60 78.3 %
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             : 
      19             : 
      20             : // Local includes
      21             : #include "libmesh/dof_map.h"
      22             : #include "libmesh/elem.h"
      23             : #include "libmesh/enum_to_string.h"
      24             : #include "libmesh/fe.h"
      25             : #include "libmesh/fe_interface.h"
      26             : #include "libmesh/fe_macro.h"
      27             : #include "libmesh/remote_elem.h"
      28             : #include "libmesh/threads.h"
      29             : 
      30             : 
      31             : #ifdef LIBMESH_ENABLE_AMR
      32             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
      33             : // to have the macro 'inf_fe_switch' available.
      34             : #include "libmesh/fe_interface_macros.h"
      35             : #include "libmesh/inf_fe.h"
      36             : #endif
      37             : #endif
      38             : 
      39             : namespace libMesh
      40             : {
      41             : 
      42             : // global helper function
      43     8613254 : void lagrange_nodal_soln(const Elem * elem,
      44             :                          const Order order,
      45             :                          const std::vector<Number> & elem_soln,
      46             :                          std::vector<Number> &       nodal_soln,
      47             :                          const bool add_p_level)
      48             : {
      49     8613254 :   const unsigned int n_nodes = elem->n_nodes();
      50     8613254 :   const ElemType type        = elem->type();
      51             : 
      52     9379633 :   const Order totalorder = order + add_p_level*elem->p_level();
      53             : 
      54     8613254 :   nodal_soln.resize(n_nodes);
      55             : 
      56             : 
      57             : 
      58     8613254 :   switch (totalorder)
      59             :     {
      60             :       // linear Lagrange shape functions
      61     7714981 :     case FIRST:
      62             :       {
      63     7714981 :         switch (type)
      64             :           {
      65         328 :           case EDGE3:
      66             :             {
      67         164 :               libmesh_assert_equal_to (elem_soln.size(), 2);
      68         164 :               libmesh_assert_equal_to (nodal_soln.size(), 3);
      69             : 
      70        1968 :               nodal_soln[0] = elem_soln[0];
      71        1968 :               nodal_soln[1] = elem_soln[1];
      72        1968 :               nodal_soln[2] = .5*(elem_soln[0] + elem_soln[1]);
      73             : 
      74        1968 :               return;
      75             :             }
      76             : 
      77           0 :           case EDGE4:
      78             :             {
      79           0 :               libmesh_assert_equal_to (elem_soln.size(), 2);
      80           0 :               libmesh_assert_equal_to (nodal_soln.size(), 4);
      81             : 
      82           0 :               nodal_soln[0] = elem_soln[0];
      83           0 :               nodal_soln[1] = elem_soln[1];
      84           0 :               nodal_soln[2] = (2.*elem_soln[0] + elem_soln[1])/3.;
      85           0 :               nodal_soln[3] = (elem_soln[0] + 2.*elem_soln[1])/3.;
      86             : 
      87           0 :               return;
      88             :             }
      89             : 
      90             : 
      91        1380 :           case TRI7:
      92         462 :             libmesh_assert_equal_to (nodal_soln.size(), 7);
      93        5532 :             nodal_soln[6] = (elem_soln[0] + elem_soln[1] + elem_soln[2])/3.;
      94             :             libmesh_fallthrough();
      95       15384 :           case TRI6:
      96             :             {
      97        1316 :               libmesh_assert (type == TRI7 || nodal_soln.size() == 6);
      98        1316 :               libmesh_assert_equal_to (elem_soln.size(), 3);
      99             : 
     100       15384 :               nodal_soln[0] = elem_soln[0];
     101       15384 :               nodal_soln[1] = elem_soln[1];
     102       15384 :               nodal_soln[2] = elem_soln[2];
     103       15384 :               nodal_soln[3] = .5*(elem_soln[0] + elem_soln[1]);
     104       15384 :               nodal_soln[4] = .5*(elem_soln[1] + elem_soln[2]);
     105       15384 :               nodal_soln[5] = .5*(elem_soln[2] + elem_soln[0]);
     106             : 
     107       15384 :               return;
     108             :             }
     109             : 
     110             : 
     111       22647 :           case QUAD8:
     112             :           case QUAD9:
     113             :             {
     114       22647 :               libmesh_assert_equal_to (elem_soln.size(), 4);
     115             : 
     116       22647 :               if (type == QUAD8)
     117           0 :                 libmesh_assert_equal_to (nodal_soln.size(), 8);
     118             :               else
     119       22647 :                 libmesh_assert_equal_to (nodal_soln.size(), 9);
     120             : 
     121             : 
     122      269869 :               nodal_soln[0] = elem_soln[0];
     123      269869 :               nodal_soln[1] = elem_soln[1];
     124      269869 :               nodal_soln[2] = elem_soln[2];
     125      269869 :               nodal_soln[3] = elem_soln[3];
     126      269869 :               nodal_soln[4] = .5*(elem_soln[0] + elem_soln[1]);
     127      269869 :               nodal_soln[5] = .5*(elem_soln[1] + elem_soln[2]);
     128      269869 :               nodal_soln[6] = .5*(elem_soln[2] + elem_soln[3]);
     129      269869 :               nodal_soln[7] = .5*(elem_soln[3] + elem_soln[0]);
     130             : 
     131      269869 :               if (type == QUAD9)
     132      269869 :                 nodal_soln[8] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3]);
     133             : 
     134       22647 :               return;
     135             :             }
     136             : 
     137             : 
     138        4608 :           case TET14:
     139        1536 :             libmesh_assert_equal_to (nodal_soln.size(), 14);
     140       18432 :             nodal_soln[10] = (elem_soln[0] + elem_soln[1] + elem_soln[2])/3.;
     141       18432 :             nodal_soln[11] = (elem_soln[0] + elem_soln[1] + elem_soln[3])/3.;
     142       18432 :             nodal_soln[12] = (elem_soln[1] + elem_soln[2] + elem_soln[3])/3.;
     143       18432 :             nodal_soln[13] = (elem_soln[0] + elem_soln[2] + elem_soln[3])/3.;
     144             :             libmesh_fallthrough();
     145       18432 :           case TET10:
     146             :             {
     147        1536 :               libmesh_assert_equal_to (elem_soln.size(), 4);
     148        1536 :               libmesh_assert (type == TET14 || nodal_soln.size() == 10);
     149             : 
     150       18432 :               nodal_soln[0] = elem_soln[0];
     151       18432 :               nodal_soln[1] = elem_soln[1];
     152       18432 :               nodal_soln[2] = elem_soln[2];
     153       18432 :               nodal_soln[3] = elem_soln[3];
     154       18432 :               nodal_soln[4] = .5*(elem_soln[0] + elem_soln[1]);
     155       18432 :               nodal_soln[5] = .5*(elem_soln[1] + elem_soln[2]);
     156       18432 :               nodal_soln[6] = .5*(elem_soln[2] + elem_soln[0]);
     157       18432 :               nodal_soln[7] = .5*(elem_soln[3] + elem_soln[0]);
     158       18432 :               nodal_soln[8] = .5*(elem_soln[3] + elem_soln[1]);
     159       18432 :               nodal_soln[9] = .5*(elem_soln[3] + elem_soln[2]);
     160             : 
     161       18432 :               return;
     162             :             }
     163             : 
     164             : 
     165        1936 :           case HEX20:
     166             :           case HEX27:
     167             :             {
     168        1936 :               libmesh_assert_equal_to (elem_soln.size(), 8);
     169             : 
     170        1936 :               if (type == HEX20)
     171           0 :                 libmesh_assert_equal_to (nodal_soln.size(), 20);
     172             :               else
     173        1936 :                 libmesh_assert_equal_to (nodal_soln.size(), 27);
     174             : 
     175       23112 :               nodal_soln[0]  = elem_soln[0];
     176       23112 :               nodal_soln[1]  = elem_soln[1];
     177       23112 :               nodal_soln[2]  = elem_soln[2];
     178       23112 :               nodal_soln[3]  = elem_soln[3];
     179       23112 :               nodal_soln[4]  = elem_soln[4];
     180       23112 :               nodal_soln[5]  = elem_soln[5];
     181       23112 :               nodal_soln[6]  = elem_soln[6];
     182       23112 :               nodal_soln[7]  = elem_soln[7];
     183       23112 :               nodal_soln[8]  = .5*(elem_soln[0] + elem_soln[1]);
     184       23112 :               nodal_soln[9]  = .5*(elem_soln[1] + elem_soln[2]);
     185       23112 :               nodal_soln[10] = .5*(elem_soln[2] + elem_soln[3]);
     186       23112 :               nodal_soln[11] = .5*(elem_soln[3] + elem_soln[0]);
     187       23112 :               nodal_soln[12] = .5*(elem_soln[0] + elem_soln[4]);
     188       23112 :               nodal_soln[13] = .5*(elem_soln[1] + elem_soln[5]);
     189       23112 :               nodal_soln[14] = .5*(elem_soln[2] + elem_soln[6]);
     190       23112 :               nodal_soln[15] = .5*(elem_soln[3] + elem_soln[7]);
     191       23112 :               nodal_soln[16] = .5*(elem_soln[4] + elem_soln[5]);
     192       23112 :               nodal_soln[17] = .5*(elem_soln[5] + elem_soln[6]);
     193       23112 :               nodal_soln[18] = .5*(elem_soln[6] + elem_soln[7]);
     194       23112 :               nodal_soln[19] = .5*(elem_soln[4] + elem_soln[7]);
     195             : 
     196       23112 :               if (type == HEX27)
     197             :                 {
     198       23112 :                   nodal_soln[20] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3]);
     199       23112 :                   nodal_soln[21] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[4] + elem_soln[5]);
     200       23112 :                   nodal_soln[22] = .25*(elem_soln[1] + elem_soln[2] + elem_soln[5] + elem_soln[6]);
     201       23112 :                   nodal_soln[23] = .25*(elem_soln[2] + elem_soln[3] + elem_soln[6] + elem_soln[7]);
     202       23112 :                   nodal_soln[24] = .25*(elem_soln[3] + elem_soln[0] + elem_soln[7] + elem_soln[4]);
     203       23112 :                   nodal_soln[25] = .25*(elem_soln[4] + elem_soln[5] + elem_soln[6] + elem_soln[7]);
     204             : 
     205       26984 :                   nodal_soln[26] = .125*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3] +
     206       21296 :                                          elem_soln[4] + elem_soln[5] + elem_soln[6] + elem_soln[7]);
     207             :                 }
     208             : 
     209        1936 :               return;
     210             :             }
     211             : 
     212             : 
     213           0 :           case PRISM21:
     214           0 :             nodal_soln[20]  = (elem_soln[9] + elem_soln[10] + elem_soln[11])/Real(3);
     215             :             libmesh_fallthrough();
     216           0 :           case PRISM20:
     217           0 :             if (type == PRISM20)
     218           0 :               libmesh_assert_equal_to (nodal_soln.size(), 20);
     219           0 :             nodal_soln[18]  = (elem_soln[0] + elem_soln[1] + elem_soln[2])/Real(3);
     220           0 :             nodal_soln[19]  = (elem_soln[3] + elem_soln[4] + elem_soln[5])/Real(3);
     221             :             libmesh_fallthrough();
     222           0 :           case PRISM18:
     223           0 :             if (type == PRISM18)
     224           0 :               libmesh_assert_equal_to (nodal_soln.size(), 18);
     225           0 :             nodal_soln[15] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[4] + elem_soln[3]);
     226           0 :             nodal_soln[16] = .25*(elem_soln[1] + elem_soln[2] + elem_soln[5] + elem_soln[4]);
     227           0 :             nodal_soln[17] = .25*(elem_soln[2] + elem_soln[0] + elem_soln[3] + elem_soln[5]);
     228             :             libmesh_fallthrough();
     229           0 :           case PRISM15:
     230             :             {
     231           0 :               libmesh_assert_equal_to (elem_soln.size(), 6);
     232             : 
     233           0 :               if (type == PRISM15)
     234           0 :                 libmesh_assert_equal_to (nodal_soln.size(), 15);
     235             : 
     236           0 :               nodal_soln[0]  = elem_soln[0];
     237           0 :               nodal_soln[1]  = elem_soln[1];
     238           0 :               nodal_soln[2]  = elem_soln[2];
     239           0 :               nodal_soln[3]  = elem_soln[3];
     240           0 :               nodal_soln[4]  = elem_soln[4];
     241           0 :               nodal_soln[5]  = elem_soln[5];
     242           0 :               nodal_soln[6]  = .5*(elem_soln[0] + elem_soln[1]);
     243           0 :               nodal_soln[7]  = .5*(elem_soln[1] + elem_soln[2]);
     244           0 :               nodal_soln[8]  = .5*(elem_soln[0] + elem_soln[2]);
     245           0 :               nodal_soln[9]  = .5*(elem_soln[0] + elem_soln[3]);
     246           0 :               nodal_soln[10] = .5*(elem_soln[1] + elem_soln[4]);
     247           0 :               nodal_soln[11] = .5*(elem_soln[2] + elem_soln[5]);
     248           0 :               nodal_soln[12] = .5*(elem_soln[3] + elem_soln[4]);
     249           0 :               nodal_soln[13] = .5*(elem_soln[4] + elem_soln[5]);
     250           0 :               nodal_soln[14] = .5*(elem_soln[3] + elem_soln[5]);
     251             : 
     252           0 :               return;
     253             :             }
     254             : 
     255           0 :           case PYRAMID18:
     256             :             {
     257           0 :               libmesh_assert_equal_to (nodal_soln.size(), 18);
     258             : 
     259           0 :               nodal_soln[14] = (elem_soln[0] + elem_soln[1] + elem_soln[4])/Real(3);
     260           0 :               nodal_soln[15] = (elem_soln[1] + elem_soln[2] + elem_soln[4])/Real(3);
     261           0 :               nodal_soln[16] = (elem_soln[2] + elem_soln[3] + elem_soln[4])/Real(3);
     262           0 :               nodal_soln[17] = (elem_soln[0] + elem_soln[3] + elem_soln[4])/Real(3);
     263             : 
     264             :               libmesh_fallthrough();
     265             :             }
     266             : 
     267           0 :           case PYRAMID14:
     268             :             {
     269           0 :               if (type == PYRAMID14)
     270           0 :                 libmesh_assert_equal_to (nodal_soln.size(), 14);
     271             : 
     272           0 :               nodal_soln[13] = .25*(elem_soln[0] + elem_soln[1] + elem_soln[2] + elem_soln[3]);
     273             : 
     274             :               libmesh_fallthrough();
     275             :             }
     276             : 
     277           0 :           case PYRAMID13:
     278             :             {
     279           0 :               libmesh_assert_equal_to (elem_soln.size(), 5);
     280             : 
     281           0 :               if (type == PYRAMID13)
     282           0 :                 libmesh_assert_equal_to (nodal_soln.size(), 13);
     283             : 
     284           0 :               nodal_soln[0]  = elem_soln[0];
     285           0 :               nodal_soln[1]  = elem_soln[1];
     286           0 :               nodal_soln[2]  = elem_soln[2];
     287           0 :               nodal_soln[3]  = elem_soln[3];
     288           0 :               nodal_soln[4]  = elem_soln[4];
     289           0 :               nodal_soln[5]  = .5*(elem_soln[0] + elem_soln[1]);
     290           0 :               nodal_soln[6]  = .5*(elem_soln[1] + elem_soln[2]);
     291           0 :               nodal_soln[7]  = .5*(elem_soln[2] + elem_soln[3]);
     292           0 :               nodal_soln[8]  = .5*(elem_soln[3] + elem_soln[0]);
     293           0 :               nodal_soln[9]  = .5*(elem_soln[0] + elem_soln[4]);
     294           0 :               nodal_soln[10] = .5*(elem_soln[1] + elem_soln[4]);
     295           0 :               nodal_soln[11] = .5*(elem_soln[2] + elem_soln[4]);
     296           0 :               nodal_soln[12] = .5*(elem_soln[3] + elem_soln[4]);
     297             : 
     298           0 :               return;
     299             :             }
     300     7386216 :           default:
     301             :             {
     302             :               // By default the element solution _is_ nodal,
     303             :               // so just copy it.
     304     7386216 :               nodal_soln = elem_soln;
     305             : 
     306     7386216 :               return;
     307             :             }
     308             :           }
     309             :       }
     310             : 
     311      890909 :     case SECOND:
     312             :       {
     313      890909 :         switch (type)
     314             :           {
     315           0 :           case EDGE4:
     316             :             {
     317           0 :               libmesh_assert_equal_to (elem_soln.size(), 3);
     318           0 :               libmesh_assert_equal_to (nodal_soln.size(), 4);
     319             : 
     320             :               // Project quadratic solution onto cubic element nodes
     321           0 :               nodal_soln[0] = elem_soln[0];
     322           0 :               nodal_soln[1] = elem_soln[1];
     323           0 :               nodal_soln[2] = (2.*elem_soln[0] - elem_soln[1] +
     324           0 :                                8.*elem_soln[2])/9.;
     325           0 :               nodal_soln[3] = (-elem_soln[0] + 2.*elem_soln[1] +
     326           0 :                                8.*elem_soln[2])/9.;
     327           0 :               return;
     328             :             }
     329             : 
     330         474 :           case TRI7:
     331             :             {
     332         474 :               libmesh_assert_equal_to (elem_soln.size(), 6);
     333         474 :               libmesh_assert_equal_to (nodal_soln.size(), 7);
     334             : 
     335       39648 :               for (int i=0; i != 6; ++i)
     336       39672 :                 nodal_soln[i] = elem_soln[i];
     337             : 
     338        6138 :               nodal_soln[6] = -1./9. * (elem_soln[0] + elem_soln[1] + elem_soln[2])
     339        5202 :                               +4./9. * (elem_soln[3] + elem_soln[4] + elem_soln[5]);
     340             : 
     341        5664 :               return;
     342             :             }
     343             : 
     344        1556 :           case TET14:
     345             :             {
     346        1556 :               libmesh_assert_equal_to (elem_soln.size(), 10);
     347        1556 :               libmesh_assert_equal_to (nodal_soln.size(), 14);
     348             : 
     349      210232 :               for (int i=0; i != 10; ++i)
     350      222240 :                 nodal_soln[i] = elem_soln[i];
     351             : 
     352       20668 :               nodal_soln[10] = -1./9. * (elem_soln[0] + elem_soln[1] + elem_soln[2])
     353       17566 :                                +4./9. * (elem_soln[4] + elem_soln[5] + elem_soln[6]);
     354       20668 :               nodal_soln[11] = -1./9. * (elem_soln[0] + elem_soln[1] + elem_soln[3])
     355       17566 :                                +4./9. * (elem_soln[4] + elem_soln[7] + elem_soln[8]);
     356       20668 :               nodal_soln[12] = -1./9. * (elem_soln[1] + elem_soln[2] + elem_soln[3])
     357       17566 :                                +4./9. * (elem_soln[5] + elem_soln[8] + elem_soln[9]);
     358       20668 :               nodal_soln[13] = -1./9. * (elem_soln[0] + elem_soln[2] + elem_soln[3])
     359       17566 :                                +4./9. * (elem_soln[6] + elem_soln[7] + elem_soln[9]);
     360             : 
     361       19112 :               return;
     362             :             }
     363             : 
     364         548 :           case PRISM21:
     365             :             {
     366        3764 :               nodal_soln[20] = -1./9. * (elem_soln[9] + elem_soln[10] + elem_soln[11])
     367        2978 :                                +4./9. * (elem_soln[15] + elem_soln[16] + elem_soln[17]);
     368             :               libmesh_fallthrough();
     369             :             }
     370         346 :           case PRISM20:
     371             :             {
     372         346 :               libmesh_assert_equal_to (elem_soln.size(), 18);
     373         346 :               if (type == PRISM20)
     374          72 :                 libmesh_assert_equal_to (nodal_soln.size(), 20);
     375             : 
     376       76152 :               for (int i=0; i != 18; ++i)
     377       84600 :                 nodal_soln[i] = elem_soln[i];
     378             : 
     379        4354 :               nodal_soln[18] = -1./9. * (elem_soln[0] + elem_soln[1] + elem_soln[2])
     380        3734 :                                +4./9. * (elem_soln[6] + elem_soln[7] + elem_soln[8]);
     381        4354 :               nodal_soln[19] = -1./9. * (elem_soln[3] + elem_soln[4] + elem_soln[5])
     382        3734 :                                +4./9. * (elem_soln[12] + elem_soln[13] + elem_soln[14]);
     383        4008 :               return;
     384             :             }
     385             : 
     386          28 :           case PYRAMID18:
     387             :             {
     388          28 :               libmesh_assert_equal_to (elem_soln.size(), 14);
     389          28 :               libmesh_assert_equal_to (nodal_soln.size(), 18);
     390             : 
     391        9660 :               for (int i=0; i != 14; ++i)
     392        9800 :                 nodal_soln[i] = elem_soln[i];
     393             : 
     394         672 :               nodal_soln[14] = -1./9. * (elem_soln[0] + elem_soln[1] + elem_soln[4])
     395         630 :                                +4./9. * (elem_soln[5] + elem_soln[9] + elem_soln[10]);
     396         672 :               nodal_soln[15] = -1./9. * (elem_soln[1] + elem_soln[2] + elem_soln[4])
     397         630 :                                +4./9. * (elem_soln[6] + elem_soln[10] + elem_soln[11]);
     398         672 :               nodal_soln[16] = -1./9. * (elem_soln[2] + elem_soln[3] + elem_soln[4])
     399         630 :                                +4./9. * (elem_soln[7] + elem_soln[11] + elem_soln[12]);
     400         672 :               nodal_soln[17] = -1./9. * (elem_soln[0] + elem_soln[3] + elem_soln[4])
     401         630 :                                +4./9. * (elem_soln[8] + elem_soln[9] + elem_soln[12]);
     402             : 
     403         644 :               return;
     404             :             }
     405             : 
     406       76186 :           default:
     407             :             {
     408             :               // By default the element solution _is_ nodal, so just
     409             :               // copy the portion relevant to the nodal solution.
     410             :               // (this is the whole nodal solution for true Lagrange
     411             :               // elements, but a smaller part for "L2 Lagrange"
     412       76186 :               libmesh_assert_less_equal(nodal_soln.size(), elem_soln.size());
     413     8647024 :               for (const auto i : index_range(nodal_soln))
     414     9161423 :                 nodal_soln[i] = elem_soln[i];
     415             : 
     416      152372 :               return;
     417             :             }
     418             :           }
     419             :       }
     420             : 
     421             : 
     422             : 
     423             : 
     424         494 :     default:
     425             :       {
     426             :         // By default the element solution _is_ nodal, so just copy
     427             :         // the portion relevant to the nodal solution.  (this is the
     428             :         // whole nodal solution for true Lagrange elements, but a
     429             :         // smaller part for "L2 Lagrange"
     430         494 :         libmesh_assert_less_equal(nodal_soln.size(), elem_soln.size());
     431      134956 :         for (const auto i : index_range(nodal_soln))
     432      145388 :           nodal_soln[i] = elem_soln[i];
     433             : 
     434         988 :         return;
     435             :       }
     436             :     }
     437             : }
     438             : 
     439             : 
     440             : // Anonymous namespace for local helper functions
     441             : namespace {
     442  1606823016 : unsigned int lagrange_n_dofs(const ElemType t, const Elem * e, const Order o)
     443             : {
     444   127635051 :   libmesh_assert(!e || e->type() == t);
     445             : 
     446  1606823016 :   switch (o)
     447             :     {
     448             :       // lagrange can only be constant on a single node
     449      147550 :     case CONSTANT:
     450             :       {
     451      147550 :         switch (t)
     452             :           {
     453       12196 :           case NODEELEM:
     454       12196 :             return 1;
     455             : 
     456           0 :           default:
     457           0 :             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
     458             :           }
     459             :       }
     460             : 
     461             :       // linear Lagrange shape functions
     462   297940106 :     case FIRST:
     463             :       {
     464   297940106 :         switch (t)
     465             :           {
     466        1352 :           case NODEELEM:
     467        1352 :             return 1;
     468             : 
     469    14591527 :           case EDGE2:
     470             :           case EDGE3:
     471             :           case EDGE4:
     472    14591527 :             return 2;
     473             : 
     474     6634635 :           case TRI3:
     475             :           case TRISHELL3:
     476             :           case TRI3SUBDIVISION:
     477             :           case TRI6:
     478             :           case TRI7:
     479     6634635 :             return 3;
     480             : 
     481    23581175 :           case QUAD4:
     482             :           case QUADSHELL4:
     483             :           case QUAD8:
     484             :           case QUADSHELL8:
     485             :           case QUAD9:
     486             :           case QUADSHELL9:
     487    23581175 :             return 4;
     488             : 
     489     1676687 :           case TET4:
     490             :           case TET10:
     491             :           case TET14:
     492     1676687 :             return 4;
     493             : 
     494    17330426 :           case HEX8:
     495             :           case HEX20:
     496             :           case HEX27:
     497    17330426 :             return 8;
     498             : 
     499     1819462 :           case PRISM6:
     500             :           case PRISM15:
     501             :           case PRISM18:
     502             :           case PRISM20:
     503             :           case PRISM21:
     504     1819462 :             return 6;
     505             : 
     506     1889444 :           case PYRAMID5:
     507             :           case PYRAMID13:
     508             :           case PYRAMID14:
     509             :           case PYRAMID18:
     510     1889444 :             return 5;
     511             : 
     512           0 :           case INVALID_ELEM:
     513           0 :             return 0;
     514             : 
     515     6223964 :           case C0POLYGON:
     516             :           case C0POLYHEDRON:
     517             :             // Polygons and polyhedra require using newer FE APIs
     518     6223964 :             if (!e)
     519           0 :               libmesh_error_msg("Code (see stack trace) used an outdated FE function overload.\n"
     520     1058150 :                                 "n_dofs() on a polygon or polyhedron is not defined by ElemType alone.");
     521     6223964 :             return e->n_nodes();
     522             : 
     523           0 :           default:
     524           0 :             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
     525             :           }
     526             :       }
     527             : 
     528             : 
     529             :       // quadratic Lagrange shape functions
     530   942027203 :     case SECOND:
     531             :       {
     532   942027203 :         switch (t)
     533             :           {
     534         195 :           case NODEELEM:
     535         195 :             return 1;
     536             : 
     537     6340729 :           case EDGE3:
     538     6340729 :             return 3;
     539             : 
     540    56011341 :           case TRI6:
     541             :           case TRI7:
     542    56011341 :             return 6;
     543             : 
     544     1376812 :           case QUAD8:
     545             :           case QUADSHELL8:
     546     1376812 :             return 8;
     547             : 
     548    31339842 :           case QUAD9:
     549             :           case QUADSHELL9:
     550    31339842 :             return 9;
     551             : 
     552   154526537 :           case TET10:
     553             :           case TET14:
     554   154526537 :             return 10;
     555             : 
     556     1977126 :           case HEX20:
     557     1977126 :             return 20;
     558             : 
     559   128449695 :           case HEX27:
     560   128449695 :             return 27;
     561             : 
     562    13615960 :           case PRISM15:
     563    13615960 :             return 15;
     564             : 
     565     3157577 :           case PRISM18:
     566             :           case PRISM20:
     567             :           case PRISM21:
     568     3157577 :             return 18;
     569             : 
     570    11529006 :           case PYRAMID13:
     571    11529006 :             return 13;
     572             : 
     573      681804 :           case PYRAMID14:
     574             :           case PYRAMID18:
     575      681804 :             return 14;
     576             : 
     577           0 :           case INVALID_ELEM:
     578           0 :             return 0;
     579             : 
     580           0 :           default:
     581           0 :             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
     582             :           }
     583             :       }
     584             : 
     585   366708157 :     case THIRD:
     586             :       {
     587   366708157 :         switch (t)
     588             :           {
     589           0 :           case NODEELEM:
     590           0 :             return 1;
     591             : 
     592        5976 :           case EDGE4:
     593        5976 :             return 4;
     594             : 
     595     2351455 :           case PRISM20:
     596     2351455 :             return 20;
     597             : 
     598     3342625 :           case PRISM21:
     599     3342625 :             return 21;
     600             : 
     601     1267451 :           case PYRAMID18:
     602     1267451 :             return 18;
     603             : 
     604    84003293 :           case TRI7:
     605    84003293 :             return 7;
     606             : 
     607    14510843 :           case TET14:
     608    14510843 :             return 14;
     609             : 
     610           0 :           case INVALID_ELEM:
     611           0 :             return 0;
     612             : 
     613           0 :           default:
     614           0 :             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
     615             :           }
     616             :       }
     617             : 
     618           0 :     default:
     619           0 :       libmesh_error_msg("ERROR: Invalid Order " << Utility::enum_to_string(o) << " selected for LAGRANGE FE family!");
     620             :     }
     621             : }
     622             : 
     623             : 
     624             : 
     625  1167007868 : unsigned int lagrange_n_dofs_at_node(const ElemType t,
     626             :                                      const Order o,
     627             :                                      const unsigned int n)
     628             : {
     629  1167007868 :   switch (o)
     630             :     {
     631             :       // lagrange can only be constant on a single node
     632           0 :     case CONSTANT:
     633             :       {
     634           0 :         switch (t)
     635             :           {
     636           0 :           case NODEELEM:
     637           0 :             return 1;
     638             : 
     639           0 :           default:
     640           0 :             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
     641             :           }
     642             :       }
     643             : 
     644             :       // linear Lagrange shape functions
     645   853483273 :     case FIRST:
     646             :       {
     647   853483273 :         switch (t)
     648             :           {
     649        1648 :           case NODEELEM:
     650        1648 :             return 1;
     651             : 
     652    26853902 :           case EDGE2:
     653             :           case EDGE3:
     654             :           case EDGE4:
     655             :             {
     656    26853902 :               switch (n)
     657             :                 {
     658     1314585 :                 case 0:
     659             :                 case 1:
     660     1314585 :                   return 1;
     661             : 
     662     1208438 :                 default:
     663     1208438 :                   return 0;
     664             :                 }
     665             :             }
     666             : 
     667    74930166 :           case TRI3:
     668             :           case TRISHELL3:
     669             :           case TRI3SUBDIVISION:
     670             :           case TRI6:
     671             :           case TRI7:
     672             :             {
     673    74930166 :               switch (n)
     674             :                 {
     675     4808583 :                 case 0:
     676             :                 case 1:
     677             :                 case 2:
     678     4808583 :                   return 1;
     679             : 
     680       20897 :                 default:
     681       20897 :                   return 0;
     682             :                 }
     683             :             }
     684             : 
     685   492903837 :           case QUAD4:
     686             :           case QUADSHELL4:
     687             :           case QUAD8:
     688             :           case QUADSHELL8:
     689             :           case QUAD9:
     690             :           case QUADSHELL9:
     691             :             {
     692   492903837 :               switch (n)
     693             :                 {
     694    42854626 :                 case 0:
     695             :                 case 1:
     696             :                 case 2:
     697             :                 case 3:
     698    42854626 :                   return 1;
     699             : 
     700     6336891 :                 default:
     701     6336891 :                   return 0;
     702             :                 }
     703             :             }
     704             : 
     705        3354 :           case C0POLYGON:
     706             :           case C0POLYHEDRON:
     707        3354 :             return 1;
     708             : 
     709             : 
     710    83978868 :           case TET4:
     711             :           case TET10:
     712             :           case TET14:
     713             :             {
     714    83978868 :               switch (n)
     715             :                 {
     716     5021973 :                 case 0:
     717             :                 case 1:
     718             :                 case 2:
     719             :                 case 3:
     720     5021973 :                   return 1;
     721             : 
     722           0 :                 default:
     723           0 :                   return 0;
     724             :                 }
     725             :             }
     726             : 
     727   166699306 :           case HEX8:
     728             :           case HEX20:
     729             :           case HEX27:
     730             :             {
     731   166699306 :               switch (n)
     732             :                 {
     733    11995643 :                 case 0:
     734             :                 case 1:
     735             :                 case 2:
     736             :                 case 3:
     737             :                 case 4:
     738             :                 case 5:
     739             :                 case 6:
     740             :                 case 7:
     741    11995643 :                   return 1;
     742             : 
     743     2577436 :                 default:
     744     2577436 :                   return 0;
     745             :                 }
     746             :             }
     747             : 
     748     4514051 :           case PRISM6:
     749             :           case PRISM15:
     750             :           case PRISM18:
     751             :           case PRISM20:
     752             :           case PRISM21:
     753             :             {
     754     4514051 :               switch (n)
     755             :                 {
     756      325171 :                 case 0:
     757             :                 case 1:
     758             :                 case 2:
     759             :                 case 3:
     760             :                 case 4:
     761             :                 case 5:
     762      325171 :                   return 1;
     763             : 
     764           0 :                 default:
     765           0 :                   return 0;
     766             :                 }
     767             :             }
     768             : 
     769     3529224 :           case PYRAMID5:
     770             :           case PYRAMID13:
     771             :           case PYRAMID14:
     772             :           case PYRAMID18:
     773             :             {
     774     3529224 :               switch (n)
     775             :                 {
     776      284414 :                 case 0:
     777             :                 case 1:
     778             :                 case 2:
     779             :                 case 3:
     780             :                 case 4:
     781      284414 :                   return 1;
     782             : 
     783           0 :                 default:
     784           0 :                   return 0;
     785             :                 }
     786             :             }
     787             : 
     788           0 :           case INVALID_ELEM:
     789           0 :             return 0;
     790             : 
     791           0 :           default:
     792           0 :             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
     793             :           }
     794             :       }
     795             : 
     796             :       // quadratic Lagrange shape functions
     797   302923934 :     case SECOND:
     798             :       {
     799   302923934 :         switch (t)
     800             :           {
     801             :             // quadratic lagrange has one dof at each node
     802    25773162 :           case NODEELEM:
     803             :           case EDGE3:
     804             :           case TRI6:
     805             :           case QUAD8:
     806             :           case QUADSHELL8:
     807             :           case QUAD9:
     808             :           case QUADSHELL9:
     809             :           case TET10:
     810             :           case HEX20:
     811             :           case HEX27:
     812             :           case PRISM15:
     813             :           case PRISM18:
     814             :           case PYRAMID13:
     815             :           case PYRAMID14:
     816    25773162 :             return 1;
     817             : 
     818     3815861 :           case PRISM20:
     819             :           case PRISM21:
     820     3815861 :             return (n < 18);
     821             : 
     822      752778 :           case PYRAMID18:
     823      752778 :             return (n < 14);
     824             : 
     825       41878 :           case TRI7:
     826       41878 :             return (n < 6);
     827             : 
     828     1130077 :           case TET14:
     829     1130077 :             return (n < 10);
     830             : 
     831           0 :           case INVALID_ELEM:
     832           0 :             return 0;
     833             : 
     834           0 :           default:
     835           0 :             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
     836             :           }
     837             :       }
     838             : 
     839    10600661 :     case THIRD:
     840             :       {
     841     9859146 :         switch (t)
     842             :           {
     843      741025 :           case NODEELEM:
     844             :           case EDGE4:
     845             :           case PRISM20:
     846             :           case PRISM21:
     847             :           case PYRAMID18:
     848             :           case TRI7:
     849             :           case TET14:
     850      741025 :             return 1;
     851             : 
     852           0 :           case INVALID_ELEM:
     853           0 :             return 0;
     854             : 
     855           0 :           default:
     856           0 :             libmesh_error_msg("ERROR: Bad ElemType = " << Utility::enum_to_string(t) << " for " << Utility::enum_to_string(o) << " order approximation!");
     857             :           }
     858             :       }
     859             : 
     860           0 :     default:
     861           0 :       libmesh_error_msg("Unsupported order: " << o );
     862             :     }
     863             : }
     864             : 
     865             : 
     866             : 
     867    90907129 : unsigned int lagrange_n_dofs_at_node(const Elem & e,
     868             :                                      const Order o,
     869             :                                      const unsigned int n)
     870             : {
     871    97563219 :   return lagrange_n_dofs_at_node(e.type(), o, n);
     872             : }
     873             : 
     874             : 
     875             : #ifdef LIBMESH_ENABLE_AMR
     876     4519284 : void lagrange_compute_constraints (DofConstraints & constraints,
     877             :                                    DofMap & dof_map,
     878             :                                    const unsigned int variable_number,
     879             :                                    const Elem * elem,
     880             :                                    const unsigned Dim)
     881             : {
     882             :   // Only constrain elements in 2,3D.
     883     4519284 :   if (Dim == 1)
     884      380840 :     return;
     885             : 
     886      422476 :   libmesh_assert(elem);
     887             : 
     888             :   // Only constrain active and ancestor elements
     889     4519284 :   if (elem->subactive())
     890       36396 :     return;
     891             : 
     892             : #ifdef LIBMESH_ENABLE_INFINITE_ELEMENTS
     893     1075098 :    if (elem->infinite())
     894             :    {
     895        3212 :       const FEType fe_t = dof_map.variable_type(variable_number);
     896             : 
     897             :       // expand the infinite_compute_constraint in its template-arguments.
     898        3212 :       switch(Dim)
     899             :       {
     900           0 :          case 2:
     901             :             {
     902           0 :             inf_fe_family_mapping_switch(2, inf_compute_constraints (constraints, dof_map, variable_number, elem) , ,; break;);
     903           0 :             break;
     904             :           }
     905        3212 :          case 3:
     906             :             {
     907        3212 :             inf_fe_family_mapping_switch(3, inf_compute_constraints (constraints, dof_map, variable_number, elem) , ,; break;);
     908        1056 :             break;
     909             :             }
     910           0 :          default:
     911           0 :            libmesh_error_msg("Invalid dim = " << Dim);
     912             :       }
     913        1056 :       return;
     914             :    }
     915             : #endif
     916             : 
     917     4138444 :   const Variable & var = dof_map.variable(variable_number);
     918     4138444 :   const FEType fe_type = var.type();
     919     4138444 :   const bool add_p_level = fe_type.p_refinement;
     920             : 
     921             :   // Pull objects out of the loop to reduce heap operations
     922      770048 :   std::vector<dof_id_type> my_dof_indices, parent_dof_indices;
     923     4440282 :   std::unique_ptr<const Elem> my_side, parent_side;
     924             : 
     925             :   // Look at the element faces.  Check to see if we need to
     926             :   // build constraints.
     927    21312890 :   for (auto s : elem->side_index_range())
     928    18767531 :     if (const Elem * const neigh = elem->neighbor_ptr(s);
     929    16110865 :         neigh && neigh != remote_elem)
     930             :       {
     931             :         // constrain dofs shared between this element and ones coarser
     932    16141919 :         if (neigh->level() < elem->level() &&
     933      318460 :             var.active_on_subdomain(neigh->subdomain_id()))
     934             :           {
     935             :             // than this element.
     936             :             // Get pointers to the elements of interest and its parent.
     937       72036 :             const Elem * parent = elem->parent();
     938             : 
     939             :             // This can't happen...  Only level-0 elements have nullptr
     940             :             // parents, and no level-0 elements can be at a higher
     941             :             // level than their neighbors!
     942       36018 :             libmesh_assert(parent);
     943             : 
     944      318118 :             elem->build_side_ptr(my_side, s);
     945      318118 :             parent->build_side_ptr(parent_side, s);
     946             : 
     947             :             // We have some elements with interior bubble function bases
     948             :             // and lower-order sides.  We need to only ask for the lower
     949             :             // order in those cases.
     950      318118 :             FEType side_fe_type = fe_type;
     951       36018 :             int extra_order = 0;
     952      318118 :             if (my_side->default_order() < fe_type.order)
     953             :               {
     954        1104 :                 side_fe_type.order = my_side->default_order();
     955        1196 :                 extra_order = (int)(side_fe_type.order) -
     956          92 :                               (int)(fe_type.order);
     957             :               }
     958             : 
     959             :             // This function gets called element-by-element, so there
     960             :             // will be a lot of memory allocation going on.  We can
     961             :             // at least minimize this for the case of the dof indices
     962             :             // by efficiently preallocating the requisite storage.
     963      318118 :             my_dof_indices.reserve (my_side->n_nodes());
     964      318118 :             parent_dof_indices.reserve (parent_side->n_nodes());
     965             : 
     966      318118 :             dof_map.dof_indices (my_side.get(), my_dof_indices,
     967       72036 :                                  variable_number, extra_order);
     968      318118 :             dof_map.dof_indices (parent_side.get(), parent_dof_indices,
     969       72036 :                                  variable_number, extra_order);
     970             : 
     971             :             const unsigned int n_side_dofs =
     972      318118 :               FEInterface::n_dofs(side_fe_type, my_side.get());
     973             :             const unsigned int n_parent_side_dofs =
     974      318118 :               FEInterface::n_dofs(side_fe_type, parent_side.get());
     975     1165482 :             for (unsigned int my_dof=0; my_dof != n_side_dofs; my_dof++)
     976             :               {
     977       93342 :                 libmesh_assert_less (my_dof, my_side->n_nodes());
     978             : 
     979             :                 // My global dof index.
     980      940706 :                 const dof_id_type my_dof_g = my_dof_indices[my_dof];
     981             : 
     982             :                 // Hunt for "constraining against myself" cases before
     983             :                 // we bother creating a constraint row
     984       93342 :                 bool self_constraint = false;
     985     2740391 :                 for (unsigned int their_dof=0;
     986     2833733 :                      their_dof != n_parent_side_dofs; their_dof++)
     987             :                   {
     988      254803 :                     libmesh_assert_less (their_dof, parent_side->n_nodes());
     989             : 
     990             :                     // Their global dof index.
     991             :                     const dof_id_type their_dof_g =
     992     2341079 :                       parent_dof_indices[their_dof];
     993             : 
     994     2341079 :                     if (their_dof_g == my_dof_g)
     995             :                       {
     996       40578 :                         self_constraint = true;
     997       40578 :                         break;
     998             :                       }
     999             :                   }
    1000             : 
    1001      847364 :                 if (self_constraint)
    1002      634219 :                   continue;
    1003             : 
    1004             :                 DofConstraintRow * constraint_row;
    1005             : 
    1006             :                 // we may be running constraint methods concurrently
    1007             :                 // on multiple threads, so we need a lock to
    1008             :                 // ensure that this constraint is "ours"
    1009             :                 {
    1010       52764 :                   Threads::spin_mutex::scoped_lock lock(Threads::spin_mtx);
    1011             : 
    1012      492654 :                   if (dof_map.is_constrained_dof(my_dof_g))
    1013       29643 :                     continue;
    1014             : 
    1015      213145 :                   constraint_row = &(constraints[my_dof_g]);
    1016       23121 :                   libmesh_assert(constraint_row->empty());
    1017             :                 }
    1018             : 
    1019             :                 // The support point of the DOF
    1020       46242 :                 const Point & support_point = my_side->point(my_dof);
    1021             : 
    1022             :                 // Figure out where my node lies on their reference element.
    1023      166903 :                 const Point mapped_point = FEMap::inverse_map(Dim-1,
    1024             :                                                               parent_side.get(),
    1025       46242 :                                                               support_point);
    1026             : 
    1027             :                 // Compute the parent's side shape function values.
    1028      700991 :                 for (unsigned int their_dof=0;
    1029      891015 :                      their_dof != n_parent_side_dofs; their_dof++)
    1030             :                   {
    1031       72838 :                     libmesh_assert_less (their_dof, parent_side->n_nodes());
    1032             : 
    1033             :                     // Their global dof index.
    1034             :                     const dof_id_type their_dof_g =
    1035      750708 :                       parent_dof_indices[their_dof];
    1036             : 
    1037      677870 :                     const Real their_dof_value = FEInterface::shape(side_fe_type,
    1038             :                                                                     parent_side.get(),
    1039             :                                                                     their_dof,
    1040      677870 :                                                                     mapped_point);
    1041             : 
    1042             :                     // Only add non-zero and non-identity values
    1043             :                     // for Lagrange basis functions.
    1044      735548 :                     if ((std::abs(their_dof_value) > 1.e-5) &&
    1045       57678 :                         (std::abs(their_dof_value) < .999))
    1046             :                       {
    1047       57678 :                         constraint_row->emplace(their_dof_g, their_dof_value);
    1048             :                       }
    1049             :   #ifdef DEBUG
    1050             :                     // Protect for the case u_i = 0.999 u_j,
    1051             :                     // in which case i better equal j.
    1052       15160 :                     else if (their_dof_value >= .999)
    1053           0 :                       libmesh_assert_equal_to (my_dof_g, their_dof_g);
    1054             :   #endif
    1055             :                   }
    1056             :               }
    1057             :           }
    1058             : 
    1059    14233820 :         if (elem->active() && add_p_level)
    1060             :           {
    1061             :             // p refinement constraints:
    1062             :             // constrain dofs shared between
    1063             :             // active elements and neighbors with
    1064             :             // lower polynomial degrees
    1065             :             const unsigned int min_p_level =
    1066    15301446 :               neigh->min_p_level_by_neighbor(elem, elem->p_level());
    1067    15301446 :             if (min_p_level < elem->p_level())
    1068           0 :               libmesh_error_msg(
    1069             :                 "Mismatched p-refinement levels for LAGRANGE is not currently supported");
    1070             :           }
    1071             :       }
    1072     3066558 : } // lagrange_compute_constraints()
    1073             : #endif // #ifdef LIBMESH_ENABLE_AMR
    1074             : 
    1075             : } // anonymous namespace
    1076             : 
    1077             : 
    1078             : // Instantiate (side_) nodal_soln() function for every dimension
    1079     8492345 : LIBMESH_FE_NODAL_SOLN(LAGRANGE, lagrange_nodal_soln)
    1080        1584 : LIBMESH_FE_SIDE_NODAL_SOLN(LAGRANGE)
    1081             : 
    1082             : 
    1083             : // Do full-specialization for every dimension, instead
    1084             : // of explicit instantiation at the end of this function.
    1085             : // This could be macro-ified.
    1086           0 : template <> unsigned int FE<0,LAGRANGE>::n_dofs(const ElemType t, const Order o) { return lagrange_n_dofs(t, nullptr, o); }
    1087           0 : template <> unsigned int FE<1,LAGRANGE>::n_dofs(const ElemType t, const Order o) { return lagrange_n_dofs(t, nullptr, o); }
    1088        1587 : template <> unsigned int FE<2,LAGRANGE>::n_dofs(const ElemType t, const Order o) { return lagrange_n_dofs(t, nullptr, o); }
    1089           0 : template <> unsigned int FE<3,LAGRANGE>::n_dofs(const ElemType t, const Order o) { return lagrange_n_dofs(t, nullptr, o); }
    1090             : 
    1091      151913 : template <> unsigned int FE<0,LAGRANGE>::n_dofs(const Elem * e, const Order o) { return lagrange_n_dofs(e->type(), e, o); }
    1092   116448380 : template <> unsigned int FE<1,LAGRANGE>::n_dofs(const Elem * e, const Order o) { return lagrange_n_dofs(e->type(), e, o); }
    1093   734849773 : template <> unsigned int FE<2,LAGRANGE>::n_dofs(const Elem * e, const Order o) { return lagrange_n_dofs(e->type(), e, o); }
    1094   755371363 : template <> unsigned int FE<3,LAGRANGE>::n_dofs(const Elem * e, const Order o) { return lagrange_n_dofs(e->type(), e, o); }
    1095             : 
    1096             : 
    1097             : // Do full-specialization for every dimension, instead
    1098             : // of explicit instantiation at the end of this function.
    1099       21135 : template <> unsigned int FE<0,LAGRANGE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(t, o, n); }
    1100    27014673 : template <> unsigned int FE<1,LAGRANGE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(t, o, n); }
    1101   776266173 : template <> unsigned int FE<2,LAGRANGE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(t, o, n); }
    1102   266142668 : template <> unsigned int FE<3,LAGRANGE>::n_dofs_at_node(const ElemType t, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(t, o, n); }
    1103             : 
    1104       23006 : template <> unsigned int FE<0,LAGRANGE>::n_dofs_at_node(const Elem & e, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(e, o, n); }
    1105       97633 : template <> unsigned int FE<1,LAGRANGE>::n_dofs_at_node(const Elem & e, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(e, o, n); }
    1106    67383137 : template <> unsigned int FE<2,LAGRANGE>::n_dofs_at_node(const Elem & e, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(e, o, n); }
    1107    30059443 : template <> unsigned int FE<3,LAGRANGE>::n_dofs_at_node(const Elem & e, const Order o, const unsigned int n) { return lagrange_n_dofs_at_node(e, o, n); }
    1108             : 
    1109             : 
    1110             : // Lagrange elements have no dofs per element
    1111             : // (just at the nodes)
    1112           0 : template <> unsigned int FE<0,LAGRANGE>::n_dofs_per_elem(const ElemType, const Order) { return 0; }
    1113           0 : template <> unsigned int FE<1,LAGRANGE>::n_dofs_per_elem(const ElemType, const Order) { return 0; }
    1114           0 : template <> unsigned int FE<2,LAGRANGE>::n_dofs_per_elem(const ElemType, const Order) { return 0; }
    1115           0 : template <> unsigned int FE<3,LAGRANGE>::n_dofs_per_elem(const ElemType, const Order) { return 0; }
    1116             : 
    1117       32638 : template <> unsigned int FE<0,LAGRANGE>::n_dofs_per_elem(const Elem &, const Order) { return 0; }
    1118     9172762 : template <> unsigned int FE<1,LAGRANGE>::n_dofs_per_elem(const Elem &, const Order) { return 0; }
    1119   166726922 : template <> unsigned int FE<2,LAGRANGE>::n_dofs_per_elem(const Elem &, const Order) { return 0; }
    1120    40926457 : template <> unsigned int FE<3,LAGRANGE>::n_dofs_per_elem(const Elem &, const Order) { return 0; }
    1121             : 
    1122             : // Lagrange FEMs are always C^0 continuous
    1123           0 : template <> FEContinuity FE<0,LAGRANGE>::get_continuity() const { return C_ZERO; }
    1124       17414 : template <> FEContinuity FE<1,LAGRANGE>::get_continuity() const { return C_ZERO; }
    1125      338313 : template <> FEContinuity FE<2,LAGRANGE>::get_continuity() const { return C_ZERO; }
    1126      161845 : template <> FEContinuity FE<3,LAGRANGE>::get_continuity() const { return C_ZERO; }
    1127             : 
    1128             : // Lagrange FEMs are not hierarchic
    1129           0 : template <> bool FE<0,LAGRANGE>::is_hierarchic() const { return false; }
    1130          24 : template <> bool FE<1,LAGRANGE>::is_hierarchic() const { return false; }
    1131         180 : template <> bool FE<2,LAGRANGE>::is_hierarchic() const { return false; }
    1132         702 : template <> bool FE<3,LAGRANGE>::is_hierarchic() const { return false; }
    1133             : 
    1134             : // Lagrange FEM shapes do not need reinit (is this always true?)
    1135        3084 : template <> bool FE<0,LAGRANGE>::shapes_need_reinit() const { return false; }
    1136       30479 : template <> bool FE<1,LAGRANGE>::shapes_need_reinit() const { return false; }
    1137   137189902 : template <> bool FE<2,LAGRANGE>::shapes_need_reinit() const { return false; }
    1138     7298177 : template <> bool FE<3,LAGRANGE>::shapes_need_reinit() const { return false; }
    1139             : 
    1140             : // Methods for computing Lagrange constraints.  Note: we pass the
    1141             : // dimension as the last argument to the anonymous helper function.
    1142             : // Also note: we only need instantiations of this function for
    1143             : // Dim==2 and 3.
    1144             : #ifdef LIBMESH_ENABLE_AMR
    1145             : template <>
    1146     3209263 : void FE<2,LAGRANGE>::compute_constraints (DofConstraints & constraints,
    1147             :                                           DofMap & dof_map,
    1148             :                                           const unsigned int variable_number,
    1149             :                                           const Elem * elem)
    1150     3209263 : { lagrange_compute_constraints(constraints, dof_map, variable_number, elem, /*Dim=*/2); }
    1151             : 
    1152             : template <>
    1153     1310021 : void FE<3,LAGRANGE>::compute_constraints (DofConstraints & constraints,
    1154             :                                           DofMap & dof_map,
    1155             :                                           const unsigned int variable_number,
    1156             :                                           const Elem * elem)
    1157     1310021 : { lagrange_compute_constraints(constraints, dof_map, variable_number, elem, /*Dim=*/3); }
    1158             : #endif // LIBMESH_ENABLE_AMR
    1159             : 
    1160             : } // namespace libMesh

Generated by: LCOV version 1.14