// Copyright (c) 2010-2023, Lawrence Livermore National Security, LLC. Produced // at the Lawrence Livermore National Laboratory. All Rights reserved. See files // LICENSE and NOTICE for details. LLNL-CODE-806117. // // This file is part of the MFEM library. For more information and source code // availability visit https://mfem.org. // // MFEM is free software; you can redistribute it and/or modify it under the // terms of the BSD-3 license. We welcome feedback and contributions, see file // CONTRIBUTING.md for details. // H1 Finite Element classes #include "fe_h1.hpp" namespace mfem { using namespace std; H1_SegmentElement::H1_SegmentElement(const int p, const int btype) : NodalTensorFiniteElement(1, p, VerifyClosed(btype), H1_DOF_MAP) { const double *cp = poly1d.ClosedPoints(p, b_type); #ifndef MFEM_THREAD_SAFE shape_x.SetSize(p+1); dshape_x.SetSize(p+1); d2shape_x.SetSize(p+1); #endif Nodes.IntPoint(0).x = cp[0]; Nodes.IntPoint(1).x = cp[p]; for (int i = 1; i < p; i++) { Nodes.IntPoint(i+1).x = cp[i]; } } void H1_SegmentElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1); #endif basis1d.Eval(ip.x, shape_x); shape(0) = shape_x(0); shape(1) = shape_x(p); for (int i = 1; i < p; i++) { shape(i+1) = shape_x(i); } } void H1_SegmentElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), dshape_x(p+1); #endif basis1d.Eval(ip.x, shape_x, dshape_x); dshape(0,0) = dshape_x(0); dshape(1,0) = dshape_x(p); for (int i = 1; i < p; i++) { dshape(i+1,0) = dshape_x(i); } } void H1_SegmentElement::CalcHessian(const IntegrationPoint &ip, DenseMatrix &Hessian) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), dshape_x(p+1), d2shape_x(p+1); #endif basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x); Hessian(0,0) = d2shape_x(0); Hessian(1,0) = d2shape_x(p); for (int i = 1; i < p; i++) { Hessian(i+1,0) = d2shape_x(i); } } void H1_SegmentElement::ProjectDelta(int vertex, Vector &dofs) const { const int p = order; const double *cp = poly1d.ClosedPoints(p, b_type); switch (vertex) { case 0: dofs(0) = poly1d.CalcDelta(p, (1.0 - cp[0])); dofs(1) = poly1d.CalcDelta(p, (1.0 - cp[p])); for (int i = 1; i < p; i++) { dofs(i+1) = poly1d.CalcDelta(p, (1.0 - cp[i])); } break; case 1: dofs(0) = poly1d.CalcDelta(p, cp[0]); dofs(1) = poly1d.CalcDelta(p, cp[p]); for (int i = 1; i < p; i++) { dofs(i+1) = poly1d.CalcDelta(p, cp[i]); } break; } } H1_QuadrilateralElement::H1_QuadrilateralElement(const int p, const int btype) : NodalTensorFiniteElement(2, p, VerifyClosed(btype), H1_DOF_MAP) { const double *cp = poly1d.ClosedPoints(p, b_type); #ifndef MFEM_THREAD_SAFE const int p1 = p + 1; shape_x.SetSize(p1); shape_y.SetSize(p1); dshape_x.SetSize(p1); dshape_y.SetSize(p1); d2shape_x.SetSize(p1); d2shape_y.SetSize(p1); #endif int o = 0; for (int j = 0; j <= p; j++) { for (int i = 0; i <= p; i++) { Nodes.IntPoint(dof_map[o++]).Set2(cp[i], cp[j]); } } } void H1_QuadrilateralElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1); #endif basis1d.Eval(ip.x, shape_x); basis1d.Eval(ip.y, shape_y); for (int o = 0, j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { shape(dof_map[o++]) = shape_x(i)*shape_y(j); } } void H1_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1); #endif basis1d.Eval(ip.x, shape_x, dshape_x); basis1d.Eval(ip.y, shape_y, dshape_y); for (int o = 0, j = 0; j <= p; j++) { for (int i = 0; i <= p; i++) { dshape(dof_map[o],0) = dshape_x(i)* shape_y(j); dshape(dof_map[o],1) = shape_x(i)*dshape_y(j); o++; } } } void H1_QuadrilateralElement::CalcHessian(const IntegrationPoint &ip, DenseMatrix &Hessian) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), dshape_x(p+1), dshape_y(p+1), d2shape_x(p+1), d2shape_y(p+1); #endif basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x); basis1d.Eval(ip.y, shape_y, dshape_y, d2shape_y); for (int o = 0, j = 0; j <= p; j++) { for (int i = 0; i <= p; i++) { Hessian(dof_map[o],0) = d2shape_x(i)* shape_y(j); Hessian(dof_map[o],1) = dshape_x(i)* dshape_y(j); Hessian(dof_map[o],2) = shape_x(i)*d2shape_y(j); o++; } } } void H1_QuadrilateralElement::ProjectDelta(int vertex, Vector &dofs) const { const int p = order; const double *cp = poly1d.ClosedPoints(p, b_type); #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1); #endif for (int i = 0; i <= p; i++) { shape_x(i) = poly1d.CalcDelta(p, (1.0 - cp[i])); shape_y(i) = poly1d.CalcDelta(p, cp[i]); } switch (vertex) { case 0: for (int o = 0, j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_x(i)*shape_x(j); } break; case 1: for (int o = 0, j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_y(i)*shape_x(j); } break; case 2: for (int o = 0, j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_y(i)*shape_y(j); } break; case 3: for (int o = 0, j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_x(i)*shape_y(j); } break; } } H1_HexahedronElement::H1_HexahedronElement(const int p, const int btype) : NodalTensorFiniteElement(3, p, VerifyClosed(btype), H1_DOF_MAP) { const double *cp = poly1d.ClosedPoints(p, b_type); #ifndef MFEM_THREAD_SAFE const int p1 = p + 1; shape_x.SetSize(p1); shape_y.SetSize(p1); shape_z.SetSize(p1); dshape_x.SetSize(p1); dshape_y.SetSize(p1); dshape_z.SetSize(p1); d2shape_x.SetSize(p1); d2shape_y.SetSize(p1); d2shape_z.SetSize(p1); #endif int o = 0; for (int k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { Nodes.IntPoint(dof_map[o++]).Set3(cp[i], cp[j], cp[k]); } } void H1_HexahedronElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), shape_z(p+1); #endif basis1d.Eval(ip.x, shape_x); basis1d.Eval(ip.y, shape_y); basis1d.Eval(ip.z, shape_z); for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { shape(dof_map[o++]) = shape_x(i)*shape_y(j)*shape_z(k); } } void H1_HexahedronElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), shape_z(p+1); Vector dshape_x(p+1), dshape_y(p+1), dshape_z(p+1); #endif basis1d.Eval(ip.x, shape_x, dshape_x); basis1d.Eval(ip.y, shape_y, dshape_y); basis1d.Eval(ip.z, shape_z, dshape_z); for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dshape(dof_map[o],0) = dshape_x(i)* shape_y(j)* shape_z(k); dshape(dof_map[o],1) = shape_x(i)*dshape_y(j)* shape_z(k); dshape(dof_map[o],2) = shape_x(i)* shape_y(j)*dshape_z(k); o++; } } void H1_HexahedronElement::CalcHessian(const IntegrationPoint &ip, DenseMatrix &Hessian) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1), shape_z(p+1); Vector dshape_x(p+1), dshape_y(p+1), dshape_z(p+1); Vector d2shape_x(p+1), d2shape_y(p+1), d2shape_z(p+1); #endif basis1d.Eval(ip.x, shape_x, dshape_x, d2shape_x); basis1d.Eval(ip.y, shape_y, dshape_y, d2shape_y); basis1d.Eval(ip.z, shape_z, dshape_z, d2shape_z); for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { Hessian(dof_map[o],0) = d2shape_x(i)* shape_y(j)* shape_z(k); Hessian(dof_map[o],1) = dshape_x(i)* dshape_y(j)* shape_z(k); Hessian(dof_map[o],2) = dshape_x(i)* shape_y(j)* dshape_z(k); Hessian(dof_map[o],3) = shape_x(i)*d2shape_y(j)* shape_z(k); Hessian(dof_map[o],4) = shape_x(i)* dshape_y(j)* dshape_z(k); Hessian(dof_map[o],5) = shape_x(i)* shape_y(j)*d2shape_z(k); o++; } } void H1_HexahedronElement::ProjectDelta(int vertex, Vector &dofs) const { const int p = order; const double *cp = poly1d.ClosedPoints(p,b_type); #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1), shape_y(p+1); #endif for (int i = 0; i <= p; i++) { shape_x(i) = poly1d.CalcDelta(p, (1.0 - cp[i])); shape_y(i) = poly1d.CalcDelta(p, cp[i]); } switch (vertex) { case 0: for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_x(i)*shape_x(j)*shape_x(k); } break; case 1: for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_y(i)*shape_x(j)*shape_x(k); } break; case 2: for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_y(i)*shape_y(j)*shape_x(k); } break; case 3: for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_x(i)*shape_y(j)*shape_x(k); } break; case 4: for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_x(i)*shape_x(j)*shape_y(k); } break; case 5: for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_y(i)*shape_x(j)*shape_y(k); } break; case 6: for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_y(i)*shape_y(j)*shape_y(k); } break; case 7: for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { dofs(dof_map[o++]) = shape_x(i)*shape_y(j)*shape_y(k); } break; } } H1_TriangleElement::H1_TriangleElement(const int p, const int btype) : NodalFiniteElement(2, Geometry::TRIANGLE, ((p + 1)*(p + 2))/2, p, FunctionSpace::Pk) { const double *cp = poly1d.ClosedPoints(p, VerifyNodal(VerifyClosed(btype))); #ifndef MFEM_THREAD_SAFE shape_x.SetSize(p + 1); shape_y.SetSize(p + 1); shape_l.SetSize(p + 1); dshape_x.SetSize(p + 1); dshape_y.SetSize(p + 1); dshape_l.SetSize(p + 1); ddshape_x.SetSize(p + 1); ddshape_y.SetSize(p + 1); ddshape_l.SetSize(p + 1); u.SetSize(dof); du.SetSize(dof, dim); ddu.SetSize(dof, (dim * (dim + 1)) / 2 ); #else Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); #endif int p2p3 = 2*p + 3; auto idx = [p2p3](int i, int j) { return ((p2p3-j)*j)/2+i; }; lex_ordering.SetSize(dof); // vertices lex_ordering[idx(0,0)] = 0; Nodes.IntPoint(0).Set2(cp[0], cp[0]); lex_ordering[idx(p,0)] = 1; Nodes.IntPoint(1).Set2(cp[p], cp[0]); lex_ordering[idx(0,p)] = 2; Nodes.IntPoint(2).Set2(cp[0], cp[p]); // edges int o = 3; for (int i = 1; i < p; i++) { lex_ordering[idx(i,0)] = o; Nodes.IntPoint(o++).Set2(cp[i], cp[0]); } for (int i = 1; i < p; i++) { lex_ordering[idx(p-i,i)] = o; Nodes.IntPoint(o++).Set2(cp[p-i], cp[i]); } for (int i = 1; i < p; i++) { lex_ordering[idx(0,p-i)] = o; Nodes.IntPoint(o++).Set2(cp[0], cp[p-i]); } // interior for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) { const double w = cp[i] + cp[j] + cp[p-i-j]; lex_ordering[idx(i,j)] = o; Nodes.IntPoint(o++).Set2(cp[i]/w, cp[j]/w); } DenseMatrix T(dof); for (int k = 0; k < dof; k++) { IntegrationPoint &ip = Nodes.IntPoint(k); poly1d.CalcBasis(p, ip.x, shape_x); poly1d.CalcBasis(p, ip.y, shape_y); poly1d.CalcBasis(p, 1. - ip.x - ip.y, shape_l); o = 0; for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) { T(o++, k) = shape_x(i)*shape_y(j)*shape_l(p-i-j); } } Ti.Factor(T); // mfem::out << "H1_TriangleElement(" << p << ") : "; Ti.TestInversion(); } void H1_TriangleElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1), u(dof); #endif poly1d.CalcBasis(p, ip.x, shape_x); poly1d.CalcBasis(p, ip.y, shape_y); poly1d.CalcBasis(p, 1. - ip.x - ip.y, shape_l); for (int o = 0, j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) { u(o++) = shape_x(i)*shape_y(j)*shape_l(p-i-j); } Ti.Mult(u, shape); } void H1_TriangleElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1); DenseMatrix du(dof, dim); #endif poly1d.CalcBasis(p, ip.x, shape_x, dshape_x); poly1d.CalcBasis(p, ip.y, shape_y, dshape_y); poly1d.CalcBasis(p, 1. - ip.x - ip.y, shape_l, dshape_l); for (int o = 0, j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) { int k = p - i - j; du(o,0) = ((dshape_x(i)* shape_l(k)) - ( shape_x(i)*dshape_l(k)))*shape_y(j); du(o,1) = ((dshape_y(j)* shape_l(k)) - ( shape_y(j)*dshape_l(k)))*shape_x(i); o++; } Ti.Mult(du, dshape); } void H1_TriangleElement::CalcHessian(const IntegrationPoint &ip, DenseMatrix &ddshape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); Vector dshape_x(p + 1), dshape_y(p + 1), dshape_l(p + 1); Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_l(p + 1); DenseMatrix ddu(dof, dim); #endif poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x); poly1d.CalcBasis(p, ip.y, shape_y, dshape_y, ddshape_y); poly1d.CalcBasis(p, 1. - ip.x - ip.y, shape_l, dshape_l, ddshape_l); for (int o = 0, j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) { int k = p - i - j; // u_xx, u_xy, u_yy ddu(o,0) = ((ddshape_x(i) * shape_l(k)) - 2. * (dshape_x(i) * dshape_l(k)) + (shape_x(i) * ddshape_l(k))) * shape_y(j); ddu(o,1) = (((shape_x(i) * ddshape_l(k)) - dshape_x(i) * dshape_l(k)) * shape_y( j)) + (((dshape_x(i) * shape_l(k)) - (shape_x(i) * dshape_l(k))) * dshape_y(j)); ddu(o,2) = ((ddshape_y(j) * shape_l(k)) - 2. * (dshape_y(j) * dshape_l(k)) + (shape_y(j) * ddshape_l(k))) * shape_x(i); o++; } Ti.Mult(ddu, ddshape); } H1_TetrahedronElement::H1_TetrahedronElement(const int p, const int btype) : NodalFiniteElement(3, Geometry::TETRAHEDRON, ((p + 1)*(p + 2)*(p + 3))/6, p, FunctionSpace::Pk) { const double *cp = poly1d.ClosedPoints(p, VerifyNodal(VerifyClosed(btype))); #ifndef MFEM_THREAD_SAFE shape_x.SetSize(p + 1); shape_y.SetSize(p + 1); shape_z.SetSize(p + 1); shape_l.SetSize(p + 1); dshape_x.SetSize(p + 1); dshape_y.SetSize(p + 1); dshape_z.SetSize(p + 1); dshape_l.SetSize(p + 1); ddshape_x.SetSize(p + 1); ddshape_y.SetSize(p + 1); ddshape_z.SetSize(p + 1); ddshape_l.SetSize(p + 1); u.SetSize(dof); du.SetSize(dof, dim); ddu.SetSize(dof, (dim * (dim + 1)) / 2); #else Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); #endif auto tri = [](int k) { return (k*(k + 1))/2; }; auto tet = [](int k) { return (k*(k + 1)*(k + 2))/6; }; int ndof = tet(p+1); auto idx = [tri, tet, p, ndof](int i, int j, int k) { return ndof - tet(p - k) - tri(p + 1 - k - j) + i; }; lex_ordering.SetSize(dof); // vertices lex_ordering[idx(0,0,0)] = 0; Nodes.IntPoint(0).Set3(cp[0], cp[0], cp[0]); lex_ordering[idx(p,0,0)] = 1; Nodes.IntPoint(1).Set3(cp[p], cp[0], cp[0]); lex_ordering[idx(0,p,0)] = 2; Nodes.IntPoint(2).Set3(cp[0], cp[p], cp[0]); lex_ordering[idx(0,0,p)] = 3; Nodes.IntPoint(3).Set3(cp[0], cp[0], cp[p]); // edges (see Tetrahedron::edges in mesh/tetrahedron.cpp) int o = 4; for (int i = 1; i < p; i++) // (0,1) { lex_ordering[idx(i,0,0)] = o; Nodes.IntPoint(o++).Set3(cp[i], cp[0], cp[0]); } for (int i = 1; i < p; i++) // (0,2) { lex_ordering[idx(0,i,0)] = o; Nodes.IntPoint(o++).Set3(cp[0], cp[i], cp[0]); } for (int i = 1; i < p; i++) // (0,3) { lex_ordering[idx(0,0,i)] = o; Nodes.IntPoint(o++).Set3(cp[0], cp[0], cp[i]); } for (int i = 1; i < p; i++) // (1,2) { lex_ordering[idx(p-i,i,0)] = o; Nodes.IntPoint(o++).Set3(cp[p-i], cp[i], cp[0]); } for (int i = 1; i < p; i++) // (1,3) { lex_ordering[idx(p-i,0,i)] = o; Nodes.IntPoint(o++).Set3(cp[p-i], cp[0], cp[i]); } for (int i = 1; i < p; i++) // (2,3) { lex_ordering[idx(0,p-i,i)] = o; Nodes.IntPoint(o++).Set3(cp[0], cp[p-i], cp[i]); } // faces (see Mesh::GenerateFaces in mesh/mesh.cpp) for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (1,2,3) { lex_ordering[idx(p-i-j,i,j)] = o; double w = cp[i] + cp[j] + cp[p-i-j]; Nodes.IntPoint(o++).Set3(cp[p-i-j]/w, cp[i]/w, cp[j]/w); } for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (0,3,2) { lex_ordering[idx(0,j,i)] = o; double w = cp[i] + cp[j] + cp[p-i-j]; Nodes.IntPoint(o++).Set3(cp[0], cp[j]/w, cp[i]/w); } for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (0,1,3) { lex_ordering[idx(i,0,j)] = o; double w = cp[i] + cp[j] + cp[p-i-j]; Nodes.IntPoint(o++).Set3(cp[i]/w, cp[0], cp[j]/w); } for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (0,2,1) { lex_ordering[idx(j,i,0)] = o; double w = cp[i] + cp[j] + cp[p-i-j]; Nodes.IntPoint(o++).Set3(cp[j]/w, cp[i]/w, cp[0]); } // interior for (int k = 1; k < p; k++) for (int j = 1; j + k < p; j++) for (int i = 1; i + j + k < p; i++) { lex_ordering[idx(i,j,k)] = o; double w = cp[i] + cp[j] + cp[k] + cp[p-i-j-k]; Nodes.IntPoint(o++).Set3(cp[i]/w, cp[j]/w, cp[k]/w); } DenseMatrix T(dof); for (int m = 0; m < dof; m++) { IntegrationPoint &ip = Nodes.IntPoint(m); poly1d.CalcBasis(p, ip.x, shape_x); poly1d.CalcBasis(p, ip.y, shape_y); poly1d.CalcBasis(p, ip.z, shape_z); poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z, shape_l); o = 0; for (int k = 0; k <= p; k++) for (int j = 0; j + k <= p; j++) for (int i = 0; i + j + k <= p; i++) { T(o++, m) = shape_x(i)*shape_y(j)*shape_z(k)*shape_l(p-i-j-k); } } Ti.Factor(T); // mfem::out << "H1_TetrahedronElement(" << p << ") : "; Ti.TestInversion(); } void H1_TetrahedronElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); Vector u(dof); #endif poly1d.CalcBasis(p, ip.x, shape_x); poly1d.CalcBasis(p, ip.y, shape_y); poly1d.CalcBasis(p, ip.z, shape_z); poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z, shape_l); for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j + k <= p; j++) for (int i = 0; i + j + k <= p; i++) { u(o++) = shape_x(i)*shape_y(j)*shape_z(k)*shape_l(p-i-j-k); } Ti.Mult(u, shape); } void H1_TetrahedronElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1); DenseMatrix du(dof, dim); #endif poly1d.CalcBasis(p, ip.x, shape_x, dshape_x); poly1d.CalcBasis(p, ip.y, shape_y, dshape_y); poly1d.CalcBasis(p, ip.z, shape_z, dshape_z); poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z, shape_l, dshape_l); for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j + k <= p; j++) for (int i = 0; i + j + k <= p; i++) { int l = p - i - j - k; du(o,0) = ((dshape_x(i)* shape_l(l)) - ( shape_x(i)*dshape_l(l)))*shape_y(j)*shape_z(k); du(o,1) = ((dshape_y(j)* shape_l(l)) - ( shape_y(j)*dshape_l(l)))*shape_x(i)*shape_z(k); du(o,2) = ((dshape_z(k)* shape_l(l)) - ( shape_z(k)*dshape_l(l)))*shape_x(i)*shape_y(j); o++; } Ti.Mult(du, dshape); } void H1_TetrahedronElement::CalcHessian(const IntegrationPoint &ip, DenseMatrix &ddshape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); Vector dshape_x(p + 1), dshape_y(p + 1), dshape_z(p + 1), dshape_l(p + 1); Vector ddshape_x(p + 1), ddshape_y(p + 1), ddshape_z(p + 1), ddshape_l(p + 1); DenseMatrix ddu(dof, ((dim + 1) * dim) / 2); #endif poly1d.CalcBasis(p, ip.x, shape_x, dshape_x, ddshape_x); poly1d.CalcBasis(p, ip.y, shape_y, dshape_y, ddshape_y); poly1d.CalcBasis(p, ip.z, shape_z, dshape_z, ddshape_z); poly1d.CalcBasis(p, 1. - ip.x - ip.y - ip.z, shape_l, dshape_l, ddshape_l); for (int o = 0, k = 0; k <= p; k++) for (int j = 0; j + k <= p; j++) for (int i = 0; i + j + k <= p; i++) { // u_xx, u_xy, u_xz, u_yy, u_yz, u_zz int l = p - i - j - k; ddu(o,0) = ((ddshape_x(i) * shape_l(l)) - 2. * (dshape_x(i) * dshape_l(l)) + (shape_x(i) * ddshape_l(l))) * shape_y(j) * shape_z(k); ddu(o,1) = ((dshape_y(j) * ((dshape_x(i) * shape_l(l)) - (shape_x(i) * dshape_l(l)))) + (shape_y(j) * ((ddshape_l(l) * shape_x(i)) - (dshape_x(i) * dshape_l(l)))))* shape_z(k); ddu(o,2) = ((dshape_z(k) * ((dshape_x(i) * shape_l(l)) - (shape_x(i) * dshape_l(l)))) + (shape_z(k) * ((ddshape_l(l) * shape_x(i)) - (dshape_x(i) * dshape_l(l)))))* shape_y(j); ddu(o,3) = ((ddshape_y(j) * shape_l(l)) - 2. * (dshape_y(j) * dshape_l(l)) + (shape_y(j) * ddshape_l(l))) * shape_x(i) * shape_z(k); ddu(o,4) = ((dshape_z(k) * ((dshape_y(j) * shape_l(l)) - (shape_y(j)*dshape_l(l))) ) + (shape_z(k)* ((ddshape_l(l)*shape_y(j)) - (dshape_y(j) * dshape_l(l)) ) ) )* shape_x(i); ddu(o,5) = ((ddshape_z(k) * shape_l(l)) - 2. * (dshape_z(k) * dshape_l(l)) + (shape_z(k) * ddshape_l(l))) * shape_y(j) * shape_x(i); o++; } Ti.Mult(ddu, ddshape); } // TODO: use a FunctionSpace specific to wedges instead of Qk. H1_WedgeElement::H1_WedgeElement(const int p, const int btype) : NodalFiniteElement(3, Geometry::PRISM, ((p + 1)*(p + 1)*(p + 2))/2, p, FunctionSpace::Qk), TriangleFE(p, btype), SegmentFE(p, btype) { #ifndef MFEM_THREAD_SAFE t_shape.SetSize(TriangleFE.GetDof()); s_shape.SetSize(SegmentFE.GetDof()); t_dshape.SetSize(TriangleFE.GetDof(), 2); s_dshape.SetSize(SegmentFE.GetDof(), 1); #endif t_dof.SetSize(dof); s_dof.SetSize(dof); int p2p3 = 2*p + 3, ntri = ((p + 1)*(p + 2))/2; auto idx = [p2p3,ntri](int i, int j, int k) { return k*ntri + ((p2p3-j)*j)/2+i; }; lex_ordering.SetSize(dof); int o = 0; // Nodal DoFs lex_ordering[idx(0,0,0)] = o++; lex_ordering[idx(p,0,0)] = o++; lex_ordering[idx(0,p,0)] = o++; lex_ordering[idx(0,0,p)] = o++; lex_ordering[idx(p,0,p)] = o++; lex_ordering[idx(0,p,p)] = o++; t_dof[0] = 0; s_dof[0] = 0; t_dof[1] = 1; s_dof[1] = 0; t_dof[2] = 2; s_dof[2] = 0; t_dof[3] = 0; s_dof[3] = 1; t_dof[4] = 1; s_dof[4] = 1; t_dof[5] = 2; s_dof[5] = 1; // Edge DoFs int k = 0; int ne = p-1; for (int i=1; i