// Copyright (c) 2010-2020, 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. // Finite Element classes #include "fe.hpp" #include "fe_coll.hpp" #include "../mesh/nurbs.hpp" #include "bilininteg.hpp" #include namespace mfem { using namespace std; FiniteElement::FiniteElement(int D, Geometry::Type G, int Do, int O, int F) : Nodes(Do) { dim = D ; geom_type = G ; dof = Do ; order = O ; func_space = F; range_type = SCALAR; map_type = VALUE; deriv_type = NONE; deriv_range_type = SCALAR; deriv_map_type = VALUE; for (int i = 0; i < Geometry::MaxDim; i++) { orders[i] = -1; } #ifndef MFEM_THREAD_SAFE vshape.SetSize(dof, dim); #endif } void FiniteElement::CalcVShape ( const IntegrationPoint &ip, DenseMatrix &shape) const { mfem_error ("FiniteElement::CalcVShape (ip, ...)\n" " is not implemented for this class!"); } void FiniteElement::CalcVShape ( ElementTransformation &Trans, DenseMatrix &shape) const { mfem_error ("FiniteElement::CalcVShape (trans, ...)\n" " is not implemented for this class!"); } void FiniteElement::CalcDivShape ( const IntegrationPoint &ip, Vector &divshape) const { mfem_error ("FiniteElement::CalcDivShape (ip, ...)\n" " is not implemented for this class!"); } void FiniteElement::CalcPhysDivShape( ElementTransformation &Trans, Vector &div_shape) const { CalcDivShape(Trans.GetIntPoint(), div_shape); div_shape *= (1.0 / Trans.Weight()); } void FiniteElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { mfem_error ("FiniteElement::CalcCurlShape (ip, ...)\n" " is not implemented for this class!"); } void FiniteElement::CalcPhysCurlShape(ElementTransformation &Trans, DenseMatrix &curl_shape) const { switch (dim) { case 3: { #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); #endif CalcCurlShape(Trans.GetIntPoint(), vshape); MultABt(vshape, Trans.Jacobian(), curl_shape); curl_shape *= (1.0 / Trans.Weight()); break; } case 2: // This is valid for both 2x2 and 3x2 Jacobians CalcCurlShape(Trans.GetIntPoint(), curl_shape); curl_shape *= (1.0 / Trans.Weight()); break; default: MFEM_ABORT("Invalid dimension, Dim = " << dim); } } void FiniteElement::GetFaceDofs(int face, int **dofs, int *ndofs) const { mfem_error ("FiniteElement::GetFaceDofs (...)"); } void FiniteElement::CalcHessian (const IntegrationPoint &ip, DenseMatrix &h) const { mfem_error ("FiniteElement::CalcHessian (...) is not overloaded !"); } void FiniteElement::GetLocalInterpolation (ElementTransformation &Trans, DenseMatrix &I) const { mfem_error ("GetLocalInterpolation (...) is not overloaded !"); } void FiniteElement::GetLocalRestriction(ElementTransformation &, DenseMatrix &) const { mfem_error("FiniteElement::GetLocalRestriction() is not overloaded !"); } void FiniteElement::GetTransferMatrix(const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const { MFEM_ABORT("method is not overloaded !"); } void FiniteElement::Project ( Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const { mfem_error ("FiniteElement::Project (...) is not overloaded !"); } void FiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { mfem_error ("FiniteElement::Project (...) (vector) is not overloaded !"); } void FiniteElement::ProjectMatrixCoefficient( MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const { mfem_error("FiniteElement::ProjectMatrixCoefficient() is not overloaded !"); } void FiniteElement::ProjectDelta(int vertex, Vector &dofs) const { mfem_error("FiniteElement::ProjectDelta(...) is not implemented for " "this element!"); } void FiniteElement::Project( const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const { mfem_error("FiniteElement::Project(...) (fe version) is not implemented " "for this element!"); } void FiniteElement::ProjectGrad( const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const { mfem_error("FiniteElement::ProjectGrad(...) is not implemented for " "this element!"); } void FiniteElement::ProjectCurl( const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const { mfem_error("FiniteElement::ProjectCurl(...) is not implemented for " "this element!"); } void FiniteElement::ProjectDiv( const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &div) const { mfem_error("FiniteElement::ProjectDiv(...) is not implemented for " "this element!"); } void FiniteElement::CalcPhysShape(ElementTransformation &Trans, Vector &shape) const { CalcShape(Trans.GetIntPoint(), shape); if (map_type == INTEGRAL) { shape /= Trans.Weight(); } } void FiniteElement::CalcPhysDShape(ElementTransformation &Trans, DenseMatrix &dshape) const { MFEM_ASSERT(map_type == VALUE, ""); #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); #endif CalcDShape(Trans.GetIntPoint(), vshape); Mult(vshape, Trans.InverseJacobian(), dshape); } void FiniteElement::CalcPhysLaplacian(ElementTransformation &Trans, Vector &Laplacian) const { MFEM_ASSERT(map_type == VALUE, ""); // Simpler routine if mapping is affine if (Trans.Hessian().FNorm2() < 1e-20) { CalcPhysLinLaplacian(Trans, Laplacian); return; } // Compute full Hessian first if non-affine int size = (dim*(dim+1))/2; DenseMatrix hess(dof, size); CalcPhysHessian(Trans,hess); if (dim == 3) { for (int nd = 0; nd < dof; nd++) { Laplacian[nd] = hess(nd,0) + hess(nd,4) + hess(nd,5); } } else if (dim == 2) { for (int nd = 0; nd < dof; nd++) { Laplacian[nd] = hess(nd,0) + hess(nd,2); } } else { for (int nd = 0; nd < dof; nd++) { Laplacian[nd] = hess(nd,0); } } } // Assume a linear mapping void FiniteElement::CalcPhysLinLaplacian(ElementTransformation &Trans, Vector &Laplacian) const { MFEM_ASSERT(map_type == VALUE, ""); int size = (dim*(dim+1))/2; DenseMatrix hess(dof, size); DenseMatrix Gij(dim,dim); Vector scale(size); CalcHessian (Trans.GetIntPoint(), hess); MultAAt(Trans.InverseJacobian(), Gij); if (dim == 3) { scale[0] = Gij(0,0); scale[1] = 2*Gij(0,1); scale[2] = 2*Gij(0,2); scale[3] = 2*Gij(1,2); scale[4] = Gij(2,2); scale[5] = Gij(1,1); } else if (dim == 2) { scale[0] = Gij(0,0); scale[1] = 2*Gij(0,1); scale[2] = Gij(1,1); } else { scale[0] = Gij(0,0); } for (int nd = 0; nd < dof; nd++) { Laplacian[nd] = 0.0; for (int ii = 0; ii < size; ii++) { Laplacian[nd] += hess(nd,ii)*scale[ii]; } } } void FiniteElement::CalcPhysHessian(ElementTransformation &Trans, DenseMatrix& Hessian) const { MFEM_ASSERT(map_type == VALUE, ""); // Roll 2-Tensors in vectors and 4-Tensor in Matrix, exploiting symmetry Array map(dim*dim); if (dim == 3) { map[0] = 0; map[1] = 1; map[2] = 2; map[3] = 1; map[4] = 5; map[5] = 3; map[6] = 2; map[7] = 3; map[8] = 4; } else if (dim == 2) { map[0] = 0; map[1] = 1; map[2] = 1; map[3] = 2; } else { map[0] = 0; } // Hessian in ref coords int size = (dim*(dim+1))/2; DenseMatrix hess(dof, size); CalcHessian(Trans.GetIntPoint(), hess); // Gradient in physical coords if (Trans.Hessian().FNorm2() > 1e-10) { DenseMatrix grad(dof, dim); CalcPhysDShape(Trans, grad); DenseMatrix gmap(dof, size); Mult(grad,Trans.Hessian(),gmap); hess -= gmap; } // LHM DenseMatrix lhm(size,size); DenseMatrix invJ = Trans.Jacobian(); lhm = 0.0; for (int i = 0; i < dim; i++) { for (int j = 0; j < dim; j++) { for (int k = 0; k < dim; k++) { for (int l = 0; l < dim; l++) { lhm(map[i*dim+j],map[k*dim+l]) += invJ(i,k)*invJ(j,l); } } } } // Correct multiplicity Vector mult(size); mult = 0.0; for (int i = 0; i < dim*dim; i++) { mult[map[i]]++; } lhm.InvRightScaling(mult); // Hessian in physical coords lhm.Invert(); Mult( hess, lhm, Hessian); } const DofToQuad &FiniteElement::GetDofToQuad(const IntegrationRule &, DofToQuad::Mode) const { mfem_error("FiniteElement::GetDofToQuad(...) is not implemented for " "this element!"); return *dof2quad_array[0]; // suppress a warning } FiniteElement::~FiniteElement() { for (int i = 0; i < dof2quad_array.Size(); i++) { delete dof2quad_array[i]; } } void ScalarFiniteElement::NodalLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I, const ScalarFiniteElement &fine_fe) const { double v[Geometry::MaxDim]; Vector vv (v, dim); IntegrationPoint f_ip; #ifdef MFEM_THREAD_SAFE Vector c_shape(dof); #endif MFEM_ASSERT(map_type == fine_fe.GetMapType(), ""); I.SetSize(fine_fe.dof, dof); for (int i = 0; i < fine_fe.dof; i++) { Trans.Transform(fine_fe.Nodes.IntPoint(i), vv); f_ip.Set(v, dim); CalcShape(f_ip, c_shape); for (int j = 0; j < dof; j++) if (fabs(I(i,j) = c_shape(j)) < 1.0e-12) { I(i,j) = 0.0; } } if (map_type == INTEGRAL) { // assuming Trans is linear; this should be ok for all refinement types Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); I *= Trans.Weight(); } } void ScalarFiniteElement::ScalarLocalInterpolation( ElementTransformation &Trans, DenseMatrix &I, const ScalarFiniteElement &fine_fe) const { // General "interpolation", defined by L2 projection double v[Geometry::MaxDim]; Vector vv (v, dim); IntegrationPoint f_ip; const int fs = fine_fe.GetDof(), cs = this->GetDof(); I.SetSize(fs, cs ); Vector fine_shape(fs), coarse_shape(cs); DenseMatrix fine_mass(fs), fine_coarse_mass(fs, cs); // initialized with 0 const int ir_order = GetOrder() + fine_fe.GetOrder(); const IntegrationRule &ir = IntRules.Get(fine_fe.GetGeomType(), ir_order); for (int i = 0; i < ir.GetNPoints(); i++) { const IntegrationPoint &ip = ir.IntPoint(i); fine_fe.CalcShape(ip, fine_shape); Trans.Transform(ip, vv); f_ip.Set(v, dim); this->CalcShape(f_ip, coarse_shape); AddMult_a_VVt(ip.weight, fine_shape, fine_mass); AddMult_a_VWt(ip.weight, fine_shape, coarse_shape, fine_coarse_mass); } DenseMatrixInverse fine_mass_inv(fine_mass); fine_mass_inv.Mult(fine_coarse_mass, I); if (map_type == INTEGRAL) { // assuming Trans is linear; this should be ok for all refinement types Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); I *= Trans.Weight(); } } const DofToQuad &ScalarFiniteElement::GetDofToQuad(const IntegrationRule &ir, DofToQuad::Mode mode) const { MFEM_VERIFY(mode == DofToQuad::FULL, "invalid mode requested"); for (int i = 0; i < dof2quad_array.Size(); i++) { const DofToQuad &d2q = *dof2quad_array[i]; if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; } } DofToQuad *d2q = new DofToQuad; const int nqpt = ir.GetNPoints(); d2q->FE = this; d2q->IntRule = &ir; d2q->mode = mode; d2q->ndof = dof; d2q->nqpt = nqpt; d2q->B.SetSize(nqpt*dof); d2q->Bt.SetSize(dof*nqpt); d2q->G.SetSize(nqpt*dim*dof); d2q->Gt.SetSize(dof*nqpt*dim); #ifdef MFEM_THREAD_SAFE Vector c_shape(dof); DenseMatrix vshape(dof, dim); #endif for (int i = 0; i < nqpt; i++) { const IntegrationPoint &ip = ir.IntPoint(i); CalcShape(ip, c_shape); for (int j = 0; j < dof; j++) { d2q->B[i+nqpt*j] = d2q->Bt[j+dof*i] = c_shape(j); } CalcDShape(ip, vshape); for (int d = 0; d < dim; d++) { for (int j = 0; j < dof; j++) { d2q->G[i+nqpt*(d+dim*j)] = d2q->Gt[j+dof*(i+nqpt*d)] = vshape(j,d); } } } dof2quad_array.Append(d2q); return *d2q; } // protected method const DofToQuad &ScalarFiniteElement::GetTensorDofToQuad( const TensorBasisElement &tb, const IntegrationRule &ir, DofToQuad::Mode mode) const { MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested"); for (int i = 0; i < dof2quad_array.Size(); i++) { const DofToQuad &d2q = *dof2quad_array[i]; if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; } } DofToQuad *d2q = new DofToQuad; const Poly_1D::Basis &basis_1d = tb.GetBasis1D(); const int ndof = order + 1; const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5); d2q->FE = this; d2q->IntRule = &ir; d2q->mode = mode; d2q->ndof = ndof; d2q->nqpt = nqpt; d2q->B.SetSize(nqpt*ndof); d2q->Bt.SetSize(ndof*nqpt); d2q->G.SetSize(nqpt*ndof); d2q->Gt.SetSize(ndof*nqpt); Vector val(ndof), grad(ndof); for (int i = 0; i < nqpt; i++) { // The first 'nqpt' points in 'ir' have the same x-coordinates as those // of the 1D rule. basis_1d.Eval(ir.IntPoint(i).x, val, grad); for (int j = 0; j < ndof; j++) { d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j); d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j); } } dof2quad_array.Append(d2q); return *d2q; } void NodalFiniteElement::ProjectCurl_2D( const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const { MFEM_ASSERT(GetMapType() == FiniteElement::INTEGRAL, ""); DenseMatrix curl_shape(fe.GetDof(), 1); curl.SetSize(dof, fe.GetDof()); for (int i = 0; i < dof; i++) { fe.CalcCurlShape(Nodes.IntPoint(i), curl_shape); for (int j = 0; j < fe.GetDof(); j++) { curl(i,j) = curl_shape(j,0); } } } void InvertLinearTrans(ElementTransformation &trans, const IntegrationPoint &pt, Vector &x) { // invert a linear transform with one Newton step IntegrationPoint p0; p0.Set3(0, 0, 0); trans.Transform(p0, x); double store[3]; Vector v(store, x.Size()); pt.Get(v, x.Size()); v -= x; trans.InverseJacobian().Mult(v, x); } void NodalFiniteElement::GetLocalRestriction(ElementTransformation &Trans, DenseMatrix &R) const { IntegrationPoint ipt; Vector pt(&ipt.x, dim); #ifdef MFEM_THREAD_SAFE Vector c_shape(dof); #endif Trans.SetIntPoint(&Nodes[0]); for (int j = 0; j < dof; j++) { InvertLinearTrans(Trans, Nodes[j], pt); if (Geometries.CheckPoint(geom_type, ipt)) // do we need an epsilon here? { CalcShape(ipt, c_shape); R.SetRow(j, c_shape); } else { // Set the whole row to avoid valgrind warnings in R.Threshold(). R.SetRow(j, infinity()); } } R.Threshold(1e-12); } void NodalFiniteElement::Project ( Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const { for (int i = 0; i < dof; i++) { const IntegrationPoint &ip = Nodes.IntPoint(i); // some coefficients expect that Trans.IntPoint is the same // as the second argument of Eval Trans.SetIntPoint(&ip); dofs(i) = coeff.Eval (Trans, ip); if (map_type == INTEGRAL) { dofs(i) *= Trans.Weight(); } } } void NodalFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { MFEM_ASSERT(dofs.Size() == vc.GetVDim()*dof, ""); Vector x(vc.GetVDim()); for (int i = 0; i < dof; i++) { const IntegrationPoint &ip = Nodes.IntPoint(i); Trans.SetIntPoint(&ip); vc.Eval (x, Trans, ip); if (map_type == INTEGRAL) { x *= Trans.Weight(); } for (int j = 0; j < x.Size(); j++) { dofs(dof*j+i) = x(j); } } } void NodalFiniteElement::ProjectMatrixCoefficient( MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const { // (mc.height x mc.width) @ DOFs -> (dof x mc.width x mc.height) in dofs MFEM_ASSERT(dofs.Size() == mc.GetHeight()*mc.GetWidth()*dof, ""); DenseMatrix MQ(mc.GetHeight(), mc.GetWidth()); for (int k = 0; k < dof; k++) { T.SetIntPoint(&Nodes.IntPoint(k)); mc.Eval(MQ, T, Nodes.IntPoint(k)); if (map_type == INTEGRAL) { MQ *= T.Weight(); } for (int r = 0; r < MQ.Height(); r++) { for (int d = 0; d < MQ.Width(); d++) { dofs(k+dof*(d+MQ.Width()*r)) = MQ(r,d); } } } } void NodalFiniteElement::Project( const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const { if (fe.GetRangeType() == SCALAR) { MFEM_ASSERT(map_type == fe.GetMapType(), ""); Vector shape(fe.GetDof()); I.SetSize(dof, fe.GetDof()); for (int k = 0; k < dof; k++) { fe.CalcShape(Nodes.IntPoint(k), shape); for (int j = 0; j < shape.Size(); j++) { I(k,j) = (fabs(shape(j)) < 1e-12) ? 0.0 : shape(j); } } } else { DenseMatrix vshape(fe.GetDof(), Trans.GetSpaceDim()); I.SetSize(vshape.Width()*dof, fe.GetDof()); for (int k = 0; k < dof; k++) { Trans.SetIntPoint(&Nodes.IntPoint(k)); fe.CalcVShape(Trans, vshape); if (map_type == INTEGRAL) { vshape *= Trans.Weight(); } for (int j = 0; j < vshape.Height(); j++) for (int d = 0; d < vshape.Width(); d++) { I(k+d*dof,j) = vshape(j,d); } } } } void NodalFiniteElement::ProjectGrad( const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const { MFEM_ASSERT(fe.GetMapType() == VALUE, ""); MFEM_ASSERT(Trans.GetSpaceDim() == dim, "") DenseMatrix dshape(fe.GetDof(), dim), grad_k(fe.GetDof(), dim), Jinv(dim); grad.SetSize(dim*dof, fe.GetDof()); for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); fe.CalcDShape(ip, dshape); Trans.SetIntPoint(&ip); CalcInverse(Trans.Jacobian(), Jinv); Mult(dshape, Jinv, grad_k); if (map_type == INTEGRAL) { grad_k *= Trans.Weight(); } for (int j = 0; j < grad_k.Height(); j++) for (int d = 0; d < dim; d++) { grad(k+d*dof,j) = grad_k(j,d); } } } void NodalFiniteElement::ProjectDiv( const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &div) const { double detJ; Vector div_shape(fe.GetDof()); div.SetSize(dof, fe.GetDof()); for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); fe.CalcDivShape(ip, div_shape); if (map_type == VALUE) { Trans.SetIntPoint(&ip); detJ = Trans.Weight(); for (int j = 0; j < div_shape.Size(); j++) { div(k,j) = (fabs(div_shape(j)) < 1e-12) ? 0.0 : div_shape(j)/detJ; } } else { for (int j = 0; j < div_shape.Size(); j++) { div(k,j) = (fabs(div_shape(j)) < 1e-12) ? 0.0 : div_shape(j); } } } } void PositiveFiniteElement::Project( Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const { for (int i = 0; i < dof; i++) { const IntegrationPoint &ip = Nodes.IntPoint(i); Trans.SetIntPoint(&ip); dofs(i) = coeff.Eval(Trans, ip); } } void PositiveFiniteElement::Project( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { MFEM_ASSERT(dofs.Size() == vc.GetVDim()*dof, ""); Vector x(vc.GetVDim()); for (int i = 0; i < dof; i++) { const IntegrationPoint &ip = Nodes.IntPoint(i); Trans.SetIntPoint(&ip); vc.Eval (x, Trans, ip); for (int j = 0; j < x.Size(); j++) { dofs(dof*j+i) = x(j); } } } void PositiveFiniteElement::Project( const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const { const NodalFiniteElement *nfe = dynamic_cast(&fe); if (nfe && dof == nfe->GetDof()) { nfe->Project(*this, Trans, I); I.Invert(); } else { // local L2 projection DenseMatrix pos_mass, mixed_mass; MassIntegrator mass_integ; mass_integ.AssembleElementMatrix(*this, Trans, pos_mass); mass_integ.AssembleElementMatrix2(fe, *this, Trans, mixed_mass); DenseMatrixInverse pos_mass_inv(pos_mass); I.SetSize(dof, fe.GetDof()); pos_mass_inv.Mult(mixed_mass, I); } } void VectorFiniteElement::CalcShape ( const IntegrationPoint &ip, Vector &shape ) const { mfem_error ("Error: Cannot use scalar CalcShape(...) function with\n" " VectorFiniteElements!"); } void VectorFiniteElement::CalcDShape ( const IntegrationPoint &ip, DenseMatrix &dshape ) const { mfem_error ("Error: Cannot use scalar CalcDShape(...) function with\n" " VectorFiniteElements!"); } void VectorFiniteElement::SetDerivMembers() { switch (map_type) { case H_DIV: deriv_type = DIV; deriv_range_type = SCALAR; deriv_map_type = INTEGRAL; break; case H_CURL: switch (dim) { case 3: // curl: 3D H_CURL -> 3D H_DIV deriv_type = CURL; deriv_range_type = VECTOR; deriv_map_type = H_DIV; break; case 2: // curl: 2D H_CURL -> INTEGRAL deriv_type = CURL; deriv_range_type = SCALAR; deriv_map_type = INTEGRAL; break; case 1: deriv_type = NONE; deriv_range_type = SCALAR; deriv_map_type = INTEGRAL; break; default: MFEM_ABORT("Invalid dimension, Dim = " << dim); } break; default: MFEM_ABORT("Invalid MapType = " << map_type); } } void VectorFiniteElement::CalcVShape_RT ( ElementTransformation &Trans, DenseMatrix &shape) const { MFEM_ASSERT(map_type == H_DIV, ""); #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); #endif CalcVShape(Trans.GetIntPoint(), vshape); MultABt(vshape, Trans.Jacobian(), shape); shape *= (1.0 / Trans.Weight()); } void VectorFiniteElement::CalcVShape_ND ( ElementTransformation &Trans, DenseMatrix &shape) const { MFEM_ASSERT(map_type == H_CURL, ""); #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); #endif CalcVShape(Trans.GetIntPoint(), vshape); Mult(vshape, Trans.InverseJacobian(), shape); } void VectorFiniteElement::Project_RT( const double *nk, const Array &d2n, VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[Geometry::MaxDim]; const int sdim = Trans.GetSpaceDim(); MFEM_ASSERT(vc.GetVDim() == sdim, ""); Vector xk(vk, sdim); const bool square_J = (dim == sdim); for (int k = 0; k < dof; k++) { Trans.SetIntPoint(&Nodes.IntPoint(k)); vc.Eval(xk, Trans, Nodes.IntPoint(k)); // dof_k = nk^t adj(J) xk dofs(k) = Trans.AdjugateJacobian().InnerProduct(vk, nk + d2n[k]*dim); if (!square_J) { dofs(k) /= Trans.Weight(); } } } void VectorFiniteElement::ProjectMatrixCoefficient_RT( const double *nk, const Array &d2n, MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const { // project the rows of the matrix coefficient in an RT space const int sdim = T.GetSpaceDim(); MFEM_ASSERT(mc.GetWidth() == sdim, ""); const bool square_J = (dim == sdim); DenseMatrix MQ(mc.GetHeight(), mc.GetWidth()); Vector nk_phys(sdim), dofs_k(MQ.Height()); MFEM_ASSERT(dofs.Size() == dof*MQ.Height(), ""); for (int k = 0; k < dof; k++) { T.SetIntPoint(&Nodes.IntPoint(k)); mc.Eval(MQ, T, Nodes.IntPoint(k)); // nk_phys = adj(J)^t nk T.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, nk_phys); if (!square_J) { nk_phys /= T.Weight(); } MQ.Mult(nk_phys, dofs_k); for (int r = 0; r < MQ.Height(); r++) { dofs(k+dof*r) = dofs_k(r); } } } void VectorFiniteElement::Project_RT( const double *nk, const Array &d2n, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const { if (fe.GetRangeType() == SCALAR) { double vk[Geometry::MaxDim]; Vector shape(fe.GetDof()); int sdim = Trans.GetSpaceDim(); I.SetSize(dof, sdim*fe.GetDof()); for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); fe.CalcShape(ip, shape); Trans.SetIntPoint(&ip); Trans.AdjugateJacobian().MultTranspose(nk + d2n[k]*dim, vk); if (fe.GetMapType() == INTEGRAL) { double w = 1.0/Trans.Weight(); for (int d = 0; d < dim; d++) { vk[d] *= w; } } for (int j = 0; j < shape.Size(); j++) { double s = shape(j); if (fabs(s) < 1e-12) { s = 0.0; } for (int d = 0; d < sdim; d++) { I(k,j+d*shape.Size()) = s*vk[d]; } } } } else { mfem_error("VectorFiniteElement::Project_RT (fe version)"); } } void VectorFiniteElement::ProjectGrad_RT( const double *nk, const Array &d2n, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const { if (dim != 2) { mfem_error("VectorFiniteElement::ProjectGrad_RT works only in 2D!"); } DenseMatrix dshape(fe.GetDof(), fe.GetDim()); Vector grad_k(fe.GetDof()); double tk[2]; grad.SetSize(dof, fe.GetDof()); for (int k = 0; k < dof; k++) { fe.CalcDShape(Nodes.IntPoint(k), dshape); tk[0] = nk[d2n[k]*dim+1]; tk[1] = -nk[d2n[k]*dim]; dshape.Mult(tk, grad_k); for (int j = 0; j < grad_k.Size(); j++) { grad(k,j) = (fabs(grad_k(j)) < 1e-12) ? 0.0 : grad_k(j); } } } void VectorFiniteElement::ProjectCurl_ND( const double *tk, const Array &d2t, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const { #ifdef MFEM_THREAD_SAFE DenseMatrix curlshape(fe.GetDof(), dim); DenseMatrix curlshape_J(fe.GetDof(), dim); DenseMatrix J(dim, dim); #else curlshape.SetSize(fe.GetDof(), dim); curlshape_J.SetSize(fe.GetDof(), dim); J.SetSize(dim, dim); #endif Vector curl_k(fe.GetDof()); curl.SetSize(dof, fe.GetDof()); for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); // calculate J^t * J / |J| Trans.SetIntPoint(&ip); MultAtB(Trans.Jacobian(), Trans.Jacobian(), J); J *= 1.0 / Trans.Weight(); // transform curl of shapes (rows) by J^t * J / |J| fe.CalcCurlShape(ip, curlshape); Mult(curlshape, J, curlshape_J); curlshape_J.Mult(tk + d2t[k]*dim, curl_k); for (int j = 0; j < curl_k.Size(); j++) { curl(k,j) = (fabs(curl_k(j)) < 1e-12) ? 0.0 : curl_k(j); } } } void VectorFiniteElement::ProjectCurl_RT( const double *nk, const Array &d2n, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &curl) const { DenseMatrix curl_shape(fe.GetDof(), dim); Vector curl_k(fe.GetDof()); curl.SetSize(dof, fe.GetDof()); for (int k = 0; k < dof; k++) { fe.CalcCurlShape(Nodes.IntPoint(k), curl_shape); curl_shape.Mult(nk + d2n[k]*dim, curl_k); for (int j = 0; j < curl_k.Size(); j++) { curl(k,j) = (fabs(curl_k(j)) < 1e-12) ? 0.0 : curl_k(j); } } } void VectorFiniteElement::Project_ND( const double *tk, const Array &d2t, VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[Geometry::MaxDim]; Vector xk(vk, vc.GetVDim()); for (int k = 0; k < dof; k++) { Trans.SetIntPoint(&Nodes.IntPoint(k)); vc.Eval(xk, Trans, Nodes.IntPoint(k)); // dof_k = xk^t J tk dofs(k) = Trans.Jacobian().InnerProduct(tk + d2t[k]*dim, vk); } } void VectorFiniteElement::ProjectMatrixCoefficient_ND( const double *tk, const Array &d2t, MatrixCoefficient &mc, ElementTransformation &T, Vector &dofs) const { // project the rows of the matrix coefficient in an ND space const int sdim = T.GetSpaceDim(); MFEM_ASSERT(mc.GetWidth() == sdim, ""); DenseMatrix MQ(mc.GetHeight(), mc.GetWidth()); Vector tk_phys(sdim), dofs_k(MQ.Height()); MFEM_ASSERT(dofs.Size() == dof*MQ.Height(), ""); for (int k = 0; k < dof; k++) { T.SetIntPoint(&Nodes.IntPoint(k)); mc.Eval(MQ, T, Nodes.IntPoint(k)); // tk_phys = J tk T.Jacobian().Mult(tk + d2t[k]*dim, tk_phys); MQ.Mult(tk_phys, dofs_k); for (int r = 0; r < MQ.Height(); r++) { dofs(k+dof*r) = dofs_k(r); } } } void VectorFiniteElement::Project_ND( const double *tk, const Array &d2t, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &I) const { if (fe.GetRangeType() == SCALAR) { int sdim = Trans.GetSpaceDim(); double vk[Geometry::MaxDim]; Vector shape(fe.GetDof()); I.SetSize(dof, sdim*fe.GetDof()); for (int k = 0; k < dof; k++) { const IntegrationPoint &ip = Nodes.IntPoint(k); fe.CalcShape(ip, shape); Trans.SetIntPoint(&ip); Trans.Jacobian().Mult(tk + d2t[k]*dim, vk); if (fe.GetMapType() == INTEGRAL) { double w = 1.0/Trans.Weight(); for (int d = 0; d < sdim; d++) { vk[d] *= w; } } for (int j = 0; j < shape.Size(); j++) { double s = shape(j); if (fabs(s) < 1e-12) { s = 0.0; } for (int d = 0; d < sdim; d++) { I(k, j + d*shape.Size()) = s*vk[d]; } } } } else { mfem_error("VectorFiniteElement::Project_ND (fe version)"); } } void VectorFiniteElement::ProjectGrad_ND( const double *tk, const Array &d2t, const FiniteElement &fe, ElementTransformation &Trans, DenseMatrix &grad) const { MFEM_ASSERT(fe.GetMapType() == VALUE, ""); DenseMatrix dshape(fe.GetDof(), fe.GetDim()); Vector grad_k(fe.GetDof()); grad.SetSize(dof, fe.GetDof()); for (int k = 0; k < dof; k++) { fe.CalcDShape(Nodes.IntPoint(k), dshape); dshape.Mult(tk + d2t[k]*dim, grad_k); for (int j = 0; j < grad_k.Size(); j++) { grad(k,j) = (fabs(grad_k(j)) < 1e-12) ? 0.0 : grad_k(j); } } } void VectorFiniteElement::LocalInterpolation_RT( const VectorFiniteElement &cfe, const double *nk, const Array &d2n, ElementTransformation &Trans, DenseMatrix &I) const { MFEM_ASSERT(map_type == cfe.GetMapType(), ""); double vk[Geometry::MaxDim]; Vector xk(vk, dim); IntegrationPoint ip; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(cfe.GetDof(), cfe.GetDim()); #else DenseMatrix vshape(cfe.vshape.Data(), cfe.GetDof(), cfe.GetDim()); #endif I.SetSize(dof, vshape.Height()); // assuming Trans is linear; this should be ok for all refinement types Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); const DenseMatrix &adjJ = Trans.AdjugateJacobian(); for (int k = 0; k < dof; k++) { Trans.Transform(Nodes.IntPoint(k), xk); ip.Set3(vk); cfe.CalcVShape(ip, vshape); // xk = |J| J^{-t} n_k adjJ.MultTranspose(nk + d2n[k]*dim, vk); // I_k = vshape_k.adj(J)^t.n_k, k=1,...,dof for (int j = 0; j < vshape.Height(); j++) { double Ikj = 0.; for (int i = 0; i < dim; i++) { Ikj += vshape(j, i) * vk[i]; } I(k, j) = (fabs(Ikj) < 1e-12) ? 0.0 : Ikj; } } } void VectorFiniteElement::LocalInterpolation_ND( const VectorFiniteElement &cfe, const double *tk, const Array &d2t, ElementTransformation &Trans, DenseMatrix &I) const { double vk[Geometry::MaxDim]; Vector xk(vk, dim); IntegrationPoint ip; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(cfe.GetDof(), cfe.GetDim()); #else DenseMatrix vshape(cfe.vshape.Data(), cfe.GetDof(), cfe.GetDim()); #endif I.SetSize(dof, vshape.Height()); // assuming Trans is linear; this should be ok for all refinement types Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); const DenseMatrix &J = Trans.Jacobian(); for (int k = 0; k < dof; k++) { Trans.Transform(Nodes.IntPoint(k), xk); ip.Set3(vk); cfe.CalcVShape(ip, vshape); // xk = J t_k J.Mult(tk + d2t[k]*dim, vk); // I_k = vshape_k.J.t_k, k=1,...,Dof for (int j = 0; j < vshape.Height(); j++) { double Ikj = 0.; for (int i = 0; i < dim; i++) { Ikj += vshape(j, i) * vk[i]; } I(k, j) = (fabs(Ikj) < 1e-12) ? 0.0 : Ikj; } } } void VectorFiniteElement::LocalRestriction_RT( const double *nk, const Array &d2n, ElementTransformation &Trans, DenseMatrix &R) const { double pt_data[Geometry::MaxDim]; IntegrationPoint ip; Vector pt(pt_data, dim); #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); #endif Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); const DenseMatrix &J = Trans.Jacobian(); const double weight = Trans.Weight(); for (int j = 0; j < dof; j++) { InvertLinearTrans(Trans, Nodes.IntPoint(j), pt); ip.Set(pt_data, dim); if (Geometries.CheckPoint(geom_type, ip)) // do we need an epsilon here? { CalcVShape(ip, vshape); J.MultTranspose(nk+dim*d2n[j], pt_data); pt /= weight; for (int k = 0; k < dof; k++) { double R_jk = 0.0; for (int d = 0; d < dim; d++) { R_jk += vshape(k,d)*pt_data[d]; } R(j,k) = R_jk; } } else { // Set the whole row to avoid valgrind warnings in R.Threshold(). R.SetRow(j, infinity()); } } R.Threshold(1e-12); } void VectorFiniteElement::LocalRestriction_ND( const double *tk, const Array &d2t, ElementTransformation &Trans, DenseMatrix &R) const { double pt_data[Geometry::MaxDim]; IntegrationPoint ip; Vector pt(pt_data, dim); #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); #endif Trans.SetIntPoint(&Geometries.GetCenter(geom_type)); const DenseMatrix &Jinv = Trans.InverseJacobian(); for (int j = 0; j < dof; j++) { InvertLinearTrans(Trans, Nodes.IntPoint(j), pt); ip.Set(pt_data, dim); if (Geometries.CheckPoint(geom_type, ip)) // do we need an epsilon here? { CalcVShape(ip, vshape); Jinv.Mult(tk+dim*d2t[j], pt_data); for (int k = 0; k < dof; k++) { double R_jk = 0.0; for (int d = 0; d < dim; d++) { R_jk += vshape(k,d)*pt_data[d]; } R(j,k) = R_jk; } } else { // Set the whole row to avoid valgrind warnings in R.Threshold(). R.SetRow(j, infinity()); } } R.Threshold(1e-12); } PointFiniteElement::PointFiniteElement() : NodalFiniteElement(0, Geometry::POINT, 1, 0) { Nodes.IntPoint(0).x = 0.0; } void PointFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1.; } void PointFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { // dshape is (1 x 0) - nothing to compute } Linear1DFiniteElement::Linear1DFiniteElement() : NodalFiniteElement(1, Geometry::SEGMENT, 2, 1) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(1).x = 1.0; } void Linear1DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1. - ip.x; shape(1) = ip.x; } void Linear1DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = -1.; dshape(1,0) = 1.; } Linear2DFiniteElement::Linear2DFiniteElement() : NodalFiniteElement(2, Geometry::TRIANGLE, 3, 1) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 1.0; } void Linear2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1. - ip.x - ip.y; shape(1) = ip.x; shape(2) = ip.y; } void Linear2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = -1.; dshape(0,1) = -1.; dshape(1,0) = 1.; dshape(1,1) = 0.; dshape(2,0) = 0.; dshape(2,1) = 1.; } BiLinear2DFiniteElement::BiLinear2DFiniteElement() : NodalFiniteElement(2, Geometry::SQUARE, 4, 1, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 1.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 1.0; } void BiLinear2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = (1. - ip.x) * (1. - ip.y) ; shape(1) = ip.x * (1. - ip.y) ; shape(2) = ip.x * ip.y ; shape(3) = (1. - ip.x) * ip.y ; } void BiLinear2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = -1. + ip.y; dshape(0,1) = -1. + ip.x ; dshape(1,0) = 1. - ip.y; dshape(1,1) = -ip.x ; dshape(2,0) = ip.y ; dshape(2,1) = ip.x ; dshape(3,0) = -ip.y ; dshape(3,1) = 1. - ip.x ; } void BiLinear2DFiniteElement::CalcHessian( const IntegrationPoint &ip, DenseMatrix &h) const { h(0,0) = 0.; h(0,1) = 1.; h(0,2) = 0.; h(1,0) = 0.; h(1,1) = -1.; h(1,2) = 0.; h(2,0) = 0.; h(2,1) = 1.; h(2,2) = 0.; h(3,0) = 0.; h(3,1) = -1.; h(3,2) = 0.; } GaussLinear2DFiniteElement::GaussLinear2DFiniteElement() : NodalFiniteElement(2, Geometry::TRIANGLE, 3, 1, FunctionSpace::Pk) { Nodes.IntPoint(0).x = 1./6.; Nodes.IntPoint(0).y = 1./6.; Nodes.IntPoint(1).x = 2./3.; Nodes.IntPoint(1).y = 1./6.; Nodes.IntPoint(2).x = 1./6.; Nodes.IntPoint(2).y = 2./3.; } void GaussLinear2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const double x = ip.x, y = ip.y; shape(0) = 5./3. - 2. * (x + y); shape(1) = 2. * (x - 1./6.); shape(2) = 2. * (y - 1./6.); } void GaussLinear2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = -2.; dshape(0,1) = -2.; dshape(1,0) = 2.; dshape(1,1) = 0.; dshape(2,0) = 0.; dshape(2,1) = 2.; } void GaussLinear2DFiniteElement::ProjectDelta(int vertex, Vector &dofs) const { dofs(vertex) = 2./3.; dofs((vertex+1)%3) = 1./6.; dofs((vertex+2)%3) = 1./6.; } // 0.5-0.5/sqrt(3) and 0.5+0.5/sqrt(3) const double GaussBiLinear2DFiniteElement::p[] = { 0.2113248654051871177454256, 0.7886751345948128822545744 }; GaussBiLinear2DFiniteElement::GaussBiLinear2DFiniteElement() : NodalFiniteElement(2, Geometry::SQUARE, 4, 1, FunctionSpace::Qk) { Nodes.IntPoint(0).x = p[0]; Nodes.IntPoint(0).y = p[0]; Nodes.IntPoint(1).x = p[1]; Nodes.IntPoint(1).y = p[0]; Nodes.IntPoint(2).x = p[1]; Nodes.IntPoint(2).y = p[1]; Nodes.IntPoint(3).x = p[0]; Nodes.IntPoint(3).y = p[1]; } void GaussBiLinear2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const double x = ip.x, y = ip.y; shape(0) = 3. * (p[1] - x) * (p[1] - y); shape(1) = 3. * (x - p[0]) * (p[1] - y); shape(2) = 3. * (x - p[0]) * (y - p[0]); shape(3) = 3. * (p[1] - x) * (y - p[0]); } void GaussBiLinear2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const double x = ip.x, y = ip.y; dshape(0,0) = 3. * (y - p[1]); dshape(0,1) = 3. * (x - p[1]); dshape(1,0) = 3. * (p[1] - y); dshape(1,1) = 3. * (p[0] - x); dshape(2,0) = 3. * (y - p[0]); dshape(2,1) = 3. * (x - p[0]); dshape(3,0) = 3. * (p[0] - y); dshape(3,1) = 3. * (p[1] - x); } void GaussBiLinear2DFiniteElement::ProjectDelta(int vertex, Vector &dofs) const { #if 1 dofs(vertex) = p[1]*p[1]; dofs((vertex+1)%4) = p[0]*p[1]; dofs((vertex+2)%4) = p[0]*p[0]; dofs((vertex+3)%4) = p[0]*p[1]; #else dofs = 1.0; #endif } P1OnQuadFiniteElement::P1OnQuadFiniteElement() : NodalFiniteElement(2, Geometry::SQUARE, 3, 1, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 1.0; } void P1OnQuadFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1. - ip.x - ip.y; shape(1) = ip.x; shape(2) = ip.y; } void P1OnQuadFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = -1.; dshape(0,1) = -1.; dshape(1,0) = 1.; dshape(1,1) = 0.; dshape(2,0) = 0.; dshape(2,1) = 1.; } Quad1DFiniteElement::Quad1DFiniteElement() : NodalFiniteElement(1, Geometry::SEGMENT, 3, 2) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(2).x = 0.5; } void Quad1DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = ip.x; double l1 = 1.0 - x, l2 = x, l3 = 2. * x - 1.; shape(0) = l1 * (-l3); shape(1) = l2 * l3; shape(2) = 4. * l1 * l2; } void Quad1DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double x = ip.x; dshape(0,0) = 4. * x - 3.; dshape(1,0) = 4. * x - 1.; dshape(2,0) = 4. - 8. * x; } QuadPos1DFiniteElement::QuadPos1DFiniteElement() : PositiveFiniteElement(1, Geometry::SEGMENT, 3, 2) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(2).x = 0.5; } void QuadPos1DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const double x = ip.x, x1 = 1. - x; shape(0) = x1 * x1; shape(1) = x * x; shape(2) = 2. * x * x1; } void QuadPos1DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const double x = ip.x; dshape(0,0) = 2. * x - 2.; dshape(1,0) = 2. * x; dshape(2,0) = 2. - 4. * x; } Quad2DFiniteElement::Quad2DFiniteElement() : NodalFiniteElement(2, Geometry::TRIANGLE, 6, 2) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(3).x = 0.5; Nodes.IntPoint(3).y = 0.0; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = 0.5; Nodes.IntPoint(5).x = 0.0; Nodes.IntPoint(5).y = 0.5; } void Quad2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = ip.x, y = ip.y; double l1 = 1.-x-y, l2 = x, l3 = y; shape(0) = l1 * (2. * l1 - 1.); shape(1) = l2 * (2. * l2 - 1.); shape(2) = l3 * (2. * l3 - 1.); shape(3) = 4. * l1 * l2; shape(4) = 4. * l2 * l3; shape(5) = 4. * l3 * l1; } void Quad2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double x = ip.x, y = ip.y; dshape(0,0) = dshape(0,1) = 4. * (x + y) - 3.; dshape(1,0) = 4. * x - 1.; dshape(1,1) = 0.; dshape(2,0) = 0.; dshape(2,1) = 4. * y - 1.; dshape(3,0) = -4. * (2. * x + y - 1.); dshape(3,1) = -4. * x; dshape(4,0) = 4. * y; dshape(4,1) = 4. * x; dshape(5,0) = -4. * y; dshape(5,1) = -4. * (x + 2. * y - 1.); } void Quad2DFiniteElement::CalcHessian (const IntegrationPoint &ip, DenseMatrix &h) const { h(0,0) = 4.; h(0,1) = 4.; h(0,2) = 4.; h(1,0) = 4.; h(1,1) = 0.; h(1,2) = 0.; h(2,0) = 0.; h(2,1) = 0.; h(2,2) = 4.; h(3,0) = -8.; h(3,1) = -4.; h(3,2) = 0.; h(4,0) = 0.; h(4,1) = 4.; h(4,2) = 0.; h(5,0) = 0.; h(5,1) = -4.; h(5,2) = -8.; } void Quad2DFiniteElement::ProjectDelta(int vertex, Vector &dofs) const { #if 0 dofs = 1.; #else dofs = 0.; dofs(vertex) = 1.; switch (vertex) { case 0: dofs(3) = 0.25; dofs(5) = 0.25; break; case 1: dofs(3) = 0.25; dofs(4) = 0.25; break; case 2: dofs(4) = 0.25; dofs(5) = 0.25; break; } #endif } const double GaussQuad2DFiniteElement::p[] = { 0.0915762135097707434595714634022015, 0.445948490915964886318329253883051 }; GaussQuad2DFiniteElement::GaussQuad2DFiniteElement() : NodalFiniteElement(2, Geometry::TRIANGLE, 6, 2), A(6), D(6,2), pol(6) { Nodes.IntPoint(0).x = p[0]; Nodes.IntPoint(0).y = p[0]; Nodes.IntPoint(1).x = 1. - 2. * p[0]; Nodes.IntPoint(1).y = p[0]; Nodes.IntPoint(2).x = p[0]; Nodes.IntPoint(2).y = 1. - 2. * p[0]; Nodes.IntPoint(3).x = p[1]; Nodes.IntPoint(3).y = p[1]; Nodes.IntPoint(4).x = 1. - 2. * p[1]; Nodes.IntPoint(4).y = p[1]; Nodes.IntPoint(5).x = p[1]; Nodes.IntPoint(5).y = 1. - 2. * p[1]; for (int i = 0; i < 6; i++) { const double x = Nodes.IntPoint(i).x, y = Nodes.IntPoint(i).y; A(0,i) = 1.; A(1,i) = x; A(2,i) = y; A(3,i) = x * x; A(4,i) = x * y; A(5,i) = y * y; } A.Invert(); } void GaussQuad2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const double x = ip.x, y = ip.y; pol(0) = 1.; pol(1) = x; pol(2) = y; pol(3) = x * x; pol(4) = x * y; pol(5) = y * y; A.Mult(pol, shape); } void GaussQuad2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const double x = ip.x, y = ip.y; D(0,0) = 0.; D(0,1) = 0.; D(1,0) = 1.; D(1,1) = 0.; D(2,0) = 0.; D(2,1) = 1.; D(3,0) = 2. * x; D(3,1) = 0.; D(4,0) = y; D(4,1) = x; D(5,0) = 0.; D(5,1) = 2. * y; Mult(A, D, dshape); } BiQuad2DFiniteElement::BiQuad2DFiniteElement() : NodalFiniteElement(2, Geometry::SQUARE, 9, 2, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 1.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 1.0; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = 0.0; Nodes.IntPoint(5).x = 1.0; Nodes.IntPoint(5).y = 0.5; Nodes.IntPoint(6).x = 0.5; Nodes.IntPoint(6).y = 1.0; Nodes.IntPoint(7).x = 0.0; Nodes.IntPoint(7).y = 0.5; Nodes.IntPoint(8).x = 0.5; Nodes.IntPoint(8).y = 0.5; } void BiQuad2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = ip.x, y = ip.y; double l1x, l2x, l3x, l1y, l2y, l3y; l1x = (x - 1.) * (2. * x - 1); l2x = 4. * x * (1. - x); l3x = x * (2. * x - 1.); l1y = (y - 1.) * (2. * y - 1); l2y = 4. * y * (1. - y); l3y = y * (2. * y - 1.); shape(0) = l1x * l1y; shape(4) = l2x * l1y; shape(1) = l3x * l1y; shape(7) = l1x * l2y; shape(8) = l2x * l2y; shape(5) = l3x * l2y; shape(3) = l1x * l3y; shape(6) = l2x * l3y; shape(2) = l3x * l3y; } void BiQuad2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double x = ip.x, y = ip.y; double l1x, l2x, l3x, l1y, l2y, l3y; double d1x, d2x, d3x, d1y, d2y, d3y; l1x = (x - 1.) * (2. * x - 1); l2x = 4. * x * (1. - x); l3x = x * (2. * x - 1.); l1y = (y - 1.) * (2. * y - 1); l2y = 4. * y * (1. - y); l3y = y * (2. * y - 1.); d1x = 4. * x - 3.; d2x = 4. - 8. * x; d3x = 4. * x - 1.; d1y = 4. * y - 3.; d2y = 4. - 8. * y; d3y = 4. * y - 1.; dshape(0,0) = d1x * l1y; dshape(0,1) = l1x * d1y; dshape(4,0) = d2x * l1y; dshape(4,1) = l2x * d1y; dshape(1,0) = d3x * l1y; dshape(1,1) = l3x * d1y; dshape(7,0) = d1x * l2y; dshape(7,1) = l1x * d2y; dshape(8,0) = d2x * l2y; dshape(8,1) = l2x * d2y; dshape(5,0) = d3x * l2y; dshape(5,1) = l3x * d2y; dshape(3,0) = d1x * l3y; dshape(3,1) = l1x * d3y; dshape(6,0) = d2x * l3y; dshape(6,1) = l2x * d3y; dshape(2,0) = d3x * l3y; dshape(2,1) = l3x * d3y; } void BiQuad2DFiniteElement::ProjectDelta(int vertex, Vector &dofs) const { #if 0 dofs = 1.; #else dofs = 0.; dofs(vertex) = 1.; switch (vertex) { case 0: dofs(4) = 0.25; dofs(7) = 0.25; break; case 1: dofs(4) = 0.25; dofs(5) = 0.25; break; case 2: dofs(5) = 0.25; dofs(6) = 0.25; break; case 3: dofs(6) = 0.25; dofs(7) = 0.25; break; } dofs(8) = 1./16.; #endif } H1Ser_QuadrilateralElement::H1Ser_QuadrilateralElement(const int p) : ScalarFiniteElement(2, Geometry::SQUARE, (p*p + 3*p +6) / 2, p, FunctionSpace::Qk) { // Store the dof_map of the associated TensorBasisElement, which will be used // to create the serendipity dof map. Its size is larger than the size of // the serendipity element. TensorBasisElement tbeTemp = TensorBasisElement(2, p, BasisType::GaussLobatto, TensorBasisElement::DofMapType::Sr_DOF_MAP); const Array tp_dof_map = tbeTemp.GetDofMap(); const double *cp = poly1d.ClosedPoints(p, BasisType::GaussLobatto); // Fixing the Nodes is exactly the same as the H1_QuadrilateralElement // constructor except we only use those values of the associated tensor // product dof_map that are <= the number of serendipity Dofs e.g. only DoFs // 0-7 out of the 9 tensor product dofs (at quadratic order) int o = 0; for (int j = 0; j <= p; j++) { for (int i = 0; i <= p; i++) { if (tp_dof_map[o] < Nodes.Size()) { Nodes.IntPoint(tp_dof_map[o]).x = cp[i]; Nodes.IntPoint(tp_dof_map[o]).y = cp[j]; } o++; } } } void H1Ser_QuadrilateralElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { int p = (this)->GetOrder(); double x = ip.x, y = ip.y; Poly_1D::Basis edgeNodalBasis(poly1d.GetBasis(p, BasisType::GaussLobatto)); Vector nodalX(p+1); Vector nodalY(p+1); edgeNodalBasis.Eval(x, nodalX); edgeNodalBasis.Eval(y, nodalY); // First, fix edge-based shape functions. Use a nodal interpolant for edge // points, weighted by the linear function that vanishes on opposite edge. for (int i = 0; i < p-1; i++) { shape(4 + 0*(p-1) + i) = (nodalX(i+1))*(1.-y); // south edge 0->1 shape(4 + 1*(p-1) + i) = (nodalY(i+1))*x; // east edge 1->2 shape(4 + 3*(p-1) - i - 1) = (nodalX(i+1)) * y; // north edge 3->2 shape(4 + 4*(p-1) - i - 1) = (nodalY(i+1)) * (1. - x); // west edge 0->3 } BiLinear2DFiniteElement bilinear = BiLinear2DFiniteElement(); Vector bilinearsAtIP(4); bilinear.CalcShape(ip, bilinearsAtIP); const double *edgePts(poly1d.ClosedPoints(p, BasisType::GaussLobatto)); // Next, set the shape function associated with vertex V, evaluated at (x,y) // to be: bilinear function associated to V, evaluated at (x,y) - sum (shape // function at edge point P, weighted by bilinear function for V evaluated at // P) where the sum is taken only for points P on edges incident to V. double vtx0fix =0; double vtx1fix =0; double vtx2fix =0; double vtx3fix =0; for (int i = 0; i 3) { double *legX = new double[p-1]; double *legY = new double[p-1]; Poly_1D *storeLegendre = new Poly_1D(); storeLegendre->CalcLegendre(p-2, x, legX); storeLegendre->CalcLegendre(p-2, y, legY); int interior_total = 0; for (int j = 4; j < p + 1; j++) { for (int k = 0; k < j-3; k++) { shape(4 + 4*(p-1) + interior_total) = legX[k] * legY[j-4-k] * x * (1. - x) * y * (1. - y); interior_total++; } } delete[] legX; delete[] legY; delete storeLegendre; } } void H1Ser_QuadrilateralElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { int p = (this)->GetOrder(); double x = ip.x, y = ip.y; Poly_1D::Basis edgeNodalBasis(poly1d.GetBasis(p, BasisType::GaussLobatto)); Vector nodalX(p+1); Vector DnodalX(p+1); Vector nodalY(p+1); Vector DnodalY(p+1); edgeNodalBasis.Eval(x, nodalX, DnodalX); edgeNodalBasis.Eval(y, nodalY, DnodalY); for (int i = 0; i < p-1; i++) { dshape(4 + 0*(p-1) + i,0) = DnodalX(i+1) * (1.-y); dshape(4 + 0*(p-1) + i,1) = -nodalX(i+1); dshape(4 + 1*(p-1) + i,0) = nodalY(i+1); dshape(4 + 1*(p-1) + i,1) = DnodalY(i+1)*x; dshape(4 + 3*(p-1) - i - 1,0) = DnodalX(i+1)*y; dshape(4 + 3*(p-1) - i - 1,1) = nodalX(i+1); dshape(4 + 4*(p-1) - i - 1,0) = -nodalY(i+1); dshape(4 + 4*(p-1) - i - 1,1) = DnodalY(i+1) * (1.-x); } BiLinear2DFiniteElement bilinear = BiLinear2DFiniteElement(); DenseMatrix DbilinearsAtIP(4); bilinear.CalcDShape(ip, DbilinearsAtIP); const double *edgePts(poly1d.ClosedPoints(p, BasisType::GaussLobatto)); dshape(0,0) = DbilinearsAtIP(0,0); dshape(0,1) = DbilinearsAtIP(0,1); dshape(1,0) = DbilinearsAtIP(1,0); dshape(1,1) = DbilinearsAtIP(1,1); dshape(2,0) = DbilinearsAtIP(2,0); dshape(2,1) = DbilinearsAtIP(2,1); dshape(3,0) = DbilinearsAtIP(3,0); dshape(3,1) = DbilinearsAtIP(3,1); for (int i = 0; i 3) { double *legX = new double[p-1]; double *legY = new double[p-1]; double *DlegX = new double[p-1]; double *DlegY = new double[p-1]; Poly_1D *storeLegendre = new Poly_1D(); storeLegendre->CalcLegendre(p-2, x, legX, DlegX); storeLegendre->CalcLegendre(p-2, y, legY, DlegY); int interior_total = 0; for (int j = 4; j < p + 1; j++) { for (int k = 0; k < j-3; k++) { dshape(4 + 4*(p-1) + interior_total, 0) = legY[j-4-k]*y*(1-y) * (DlegX[k]*x*(1-x) + legX[k]*(1-2*x)); dshape(4 + 4*(p-1) + interior_total, 1) = legX[k]*x*(1-x) * (DlegY[j-4-k]*y*(1-y) + legY[j-4-k]*(1-2*y)); interior_total++; } } delete[] legX; delete[] legY; delete[] DlegX; delete[] DlegY; delete storeLegendre; } } void H1Ser_QuadrilateralElement::GetLocalInterpolation(ElementTransformation &Trans, DenseMatrix &I) const { // For p<=4, the basis is nodal; for p>4, the quad-interior functions are // non-nodal. if (order <= 4) { NodalLocalInterpolation(Trans, I, *this); } else { ScalarLocalInterpolation(Trans, I, *this); } } BiQuadPos2DFiniteElement::BiQuadPos2DFiniteElement() : PositiveFiniteElement(2, Geometry::SQUARE, 9, 2, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 1.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 1.0; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = 0.0; Nodes.IntPoint(5).x = 1.0; Nodes.IntPoint(5).y = 0.5; Nodes.IntPoint(6).x = 0.5; Nodes.IntPoint(6).y = 1.0; Nodes.IntPoint(7).x = 0.0; Nodes.IntPoint(7).y = 0.5; Nodes.IntPoint(8).x = 0.5; Nodes.IntPoint(8).y = 0.5; } void BiQuadPos2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = ip.x, y = ip.y; double l1x, l2x, l3x, l1y, l2y, l3y; l1x = (1. - x) * (1. - x); l2x = 2. * x * (1. - x); l3x = x * x; l1y = (1. - y) * (1. - y); l2y = 2. * y * (1. - y); l3y = y * y; shape(0) = l1x * l1y; shape(4) = l2x * l1y; shape(1) = l3x * l1y; shape(7) = l1x * l2y; shape(8) = l2x * l2y; shape(5) = l3x * l2y; shape(3) = l1x * l3y; shape(6) = l2x * l3y; shape(2) = l3x * l3y; } void BiQuadPos2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double x = ip.x, y = ip.y; double l1x, l2x, l3x, l1y, l2y, l3y; double d1x, d2x, d3x, d1y, d2y, d3y; l1x = (1. - x) * (1. - x); l2x = 2. * x * (1. - x); l3x = x * x; l1y = (1. - y) * (1. - y); l2y = 2. * y * (1. - y); l3y = y * y; d1x = 2. * x - 2.; d2x = 2. - 4. * x; d3x = 2. * x; d1y = 2. * y - 2.; d2y = 2. - 4. * y; d3y = 2. * y; dshape(0,0) = d1x * l1y; dshape(0,1) = l1x * d1y; dshape(4,0) = d2x * l1y; dshape(4,1) = l2x * d1y; dshape(1,0) = d3x * l1y; dshape(1,1) = l3x * d1y; dshape(7,0) = d1x * l2y; dshape(7,1) = l1x * d2y; dshape(8,0) = d2x * l2y; dshape(8,1) = l2x * d2y; dshape(5,0) = d3x * l2y; dshape(5,1) = l3x * d2y; dshape(3,0) = d1x * l3y; dshape(3,1) = l1x * d3y; dshape(6,0) = d2x * l3y; dshape(6,1) = l2x * d3y; dshape(2,0) = d3x * l3y; dshape(2,1) = l3x * d3y; } void BiQuadPos2DFiniteElement::GetLocalInterpolation( ElementTransformation &Trans, DenseMatrix &I) const { double s[9]; IntegrationPoint tr_ip; Vector xx(&tr_ip.x, 2), shape(s, 9); for (int i = 0; i < 9; i++) { Trans.Transform(Nodes.IntPoint(i), xx); CalcShape(tr_ip, shape); for (int j = 0; j < 9; j++) if (fabs(I(i,j) = s[j]) < 1.0e-12) { I(i,j) = 0.0; } } for (int i = 0; i < 9; i++) { double *d = &I(0,i); d[4] = 2. * d[4] - 0.5 * (d[0] + d[1]); d[5] = 2. * d[5] - 0.5 * (d[1] + d[2]); d[6] = 2. * d[6] - 0.5 * (d[2] + d[3]); d[7] = 2. * d[7] - 0.5 * (d[3] + d[0]); d[8] = 4. * d[8] - 0.5 * (d[4] + d[5] + d[6] + d[7]) - 0.25 * (d[0] + d[1] + d[2] + d[3]); } } void BiQuadPos2DFiniteElement::Project( Coefficient &coeff, ElementTransformation &Trans, Vector &dofs) const { double *d = dofs; for (int i = 0; i < 9; i++) { const IntegrationPoint &ip = Nodes.IntPoint(i); Trans.SetIntPoint(&ip); d[i] = coeff.Eval(Trans, ip); } d[4] = 2. * d[4] - 0.5 * (d[0] + d[1]); d[5] = 2. * d[5] - 0.5 * (d[1] + d[2]); d[6] = 2. * d[6] - 0.5 * (d[2] + d[3]); d[7] = 2. * d[7] - 0.5 * (d[3] + d[0]); d[8] = 4. * d[8] - 0.5 * (d[4] + d[5] + d[6] + d[7]) - 0.25 * (d[0] + d[1] + d[2] + d[3]); } void BiQuadPos2DFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double v[3]; Vector x (v, vc.GetVDim()); for (int i = 0; i < 9; i++) { const IntegrationPoint &ip = Nodes.IntPoint(i); Trans.SetIntPoint(&ip); vc.Eval (x, Trans, ip); for (int j = 0; j < x.Size(); j++) { dofs(9*j+i) = v[j]; } } for (int j = 0; j < x.Size(); j++) { double *d = &dofs(9*j); d[4] = 2. * d[4] - 0.5 * (d[0] + d[1]); d[5] = 2. * d[5] - 0.5 * (d[1] + d[2]); d[6] = 2. * d[6] - 0.5 * (d[2] + d[3]); d[7] = 2. * d[7] - 0.5 * (d[3] + d[0]); d[8] = 4. * d[8] - 0.5 * (d[4] + d[5] + d[6] + d[7]) - 0.25 * (d[0] + d[1] + d[2] + d[3]); } } GaussBiQuad2DFiniteElement::GaussBiQuad2DFiniteElement() : NodalFiniteElement(2, Geometry::SQUARE, 9, 2, FunctionSpace::Qk) { const double p1 = 0.5*(1.-sqrt(3./5.)); Nodes.IntPoint(0).x = p1; Nodes.IntPoint(0).y = p1; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = p1; Nodes.IntPoint(1).x = 1.-p1; Nodes.IntPoint(1).y = p1; Nodes.IntPoint(7).x = p1; Nodes.IntPoint(7).y = 0.5; Nodes.IntPoint(8).x = 0.5; Nodes.IntPoint(8).y = 0.5; Nodes.IntPoint(5).x = 1.-p1; Nodes.IntPoint(5).y = 0.5; Nodes.IntPoint(3).x = p1; Nodes.IntPoint(3).y = 1.-p1; Nodes.IntPoint(6).x = 0.5; Nodes.IntPoint(6).y = 1.-p1; Nodes.IntPoint(2).x = 1.-p1; Nodes.IntPoint(2).y = 1.-p1; } void GaussBiQuad2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const double a = sqrt(5./3.); const double p1 = 0.5*(1.-sqrt(3./5.)); double x = a*(ip.x-p1), y = a*(ip.y-p1); double l1x, l2x, l3x, l1y, l2y, l3y; l1x = (x - 1.) * (2. * x - 1); l2x = 4. * x * (1. - x); l3x = x * (2. * x - 1.); l1y = (y - 1.) * (2. * y - 1); l2y = 4. * y * (1. - y); l3y = y * (2. * y - 1.); shape(0) = l1x * l1y; shape(4) = l2x * l1y; shape(1) = l3x * l1y; shape(7) = l1x * l2y; shape(8) = l2x * l2y; shape(5) = l3x * l2y; shape(3) = l1x * l3y; shape(6) = l2x * l3y; shape(2) = l3x * l3y; } void GaussBiQuad2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const double a = sqrt(5./3.); const double p1 = 0.5*(1.-sqrt(3./5.)); double x = a*(ip.x-p1), y = a*(ip.y-p1); double l1x, l2x, l3x, l1y, l2y, l3y; double d1x, d2x, d3x, d1y, d2y, d3y; l1x = (x - 1.) * (2. * x - 1); l2x = 4. * x * (1. - x); l3x = x * (2. * x - 1.); l1y = (y - 1.) * (2. * y - 1); l2y = 4. * y * (1. - y); l3y = y * (2. * y - 1.); d1x = a * (4. * x - 3.); d2x = a * (4. - 8. * x); d3x = a * (4. * x - 1.); d1y = a * (4. * y - 3.); d2y = a * (4. - 8. * y); d3y = a * (4. * y - 1.); dshape(0,0) = d1x * l1y; dshape(0,1) = l1x * d1y; dshape(4,0) = d2x * l1y; dshape(4,1) = l2x * d1y; dshape(1,0) = d3x * l1y; dshape(1,1) = l3x * d1y; dshape(7,0) = d1x * l2y; dshape(7,1) = l1x * d2y; dshape(8,0) = d2x * l2y; dshape(8,1) = l2x * d2y; dshape(5,0) = d3x * l2y; dshape(5,1) = l3x * d2y; dshape(3,0) = d1x * l3y; dshape(3,1) = l1x * d3y; dshape(6,0) = d2x * l3y; dshape(6,1) = l2x * d3y; dshape(2,0) = d3x * l3y; dshape(2,1) = l3x * d3y; } BiCubic2DFiniteElement::BiCubic2DFiniteElement() : NodalFiniteElement (2, Geometry::SQUARE, 16, 3, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.; Nodes.IntPoint(0).y = 0.; Nodes.IntPoint(1).x = 1.; Nodes.IntPoint(1).y = 0.; Nodes.IntPoint(2).x = 1.; Nodes.IntPoint(2).y = 1.; Nodes.IntPoint(3).x = 0.; Nodes.IntPoint(3).y = 1.; Nodes.IntPoint(4).x = 1./3.; Nodes.IntPoint(4).y = 0.; Nodes.IntPoint(5).x = 2./3.; Nodes.IntPoint(5).y = 0.; Nodes.IntPoint(6).x = 1.; Nodes.IntPoint(6).y = 1./3.; Nodes.IntPoint(7).x = 1.; Nodes.IntPoint(7).y = 2./3.; Nodes.IntPoint(8).x = 2./3.; Nodes.IntPoint(8).y = 1.; Nodes.IntPoint(9).x = 1./3.; Nodes.IntPoint(9).y = 1.; Nodes.IntPoint(10).x = 0.; Nodes.IntPoint(10).y = 2./3.; Nodes.IntPoint(11).x = 0.; Nodes.IntPoint(11).y = 1./3.; Nodes.IntPoint(12).x = 1./3.; Nodes.IntPoint(12).y = 1./3.; Nodes.IntPoint(13).x = 2./3.; Nodes.IntPoint(13).y = 1./3.; Nodes.IntPoint(14).x = 1./3.; Nodes.IntPoint(14).y = 2./3.; Nodes.IntPoint(15).x = 2./3.; Nodes.IntPoint(15).y = 2./3.; } void BiCubic2DFiniteElement::CalcShape( const IntegrationPoint &ip, Vector &shape) const { double x = ip.x, y = ip.y; double w1x, w2x, w3x, w1y, w2y, w3y; double l0x, l1x, l2x, l3x, l0y, l1y, l2y, l3y; w1x = x - 1./3.; w2x = x - 2./3.; w3x = x - 1.; w1y = y - 1./3.; w2y = y - 2./3.; w3y = y - 1.; l0x = (- 4.5) * w1x * w2x * w3x; l1x = ( 13.5) * x * w2x * w3x; l2x = (-13.5) * x * w1x * w3x; l3x = ( 4.5) * x * w1x * w2x; l0y = (- 4.5) * w1y * w2y * w3y; l1y = ( 13.5) * y * w2y * w3y; l2y = (-13.5) * y * w1y * w3y; l3y = ( 4.5) * y * w1y * w2y; shape(0) = l0x * l0y; shape(1) = l3x * l0y; shape(2) = l3x * l3y; shape(3) = l0x * l3y; shape(4) = l1x * l0y; shape(5) = l2x * l0y; shape(6) = l3x * l1y; shape(7) = l3x * l2y; shape(8) = l2x * l3y; shape(9) = l1x * l3y; shape(10) = l0x * l2y; shape(11) = l0x * l1y; shape(12) = l1x * l1y; shape(13) = l2x * l1y; shape(14) = l1x * l2y; shape(15) = l2x * l2y; } void BiCubic2DFiniteElement::CalcDShape( const IntegrationPoint &ip, DenseMatrix &dshape) const { double x = ip.x, y = ip.y; double w1x, w2x, w3x, w1y, w2y, w3y; double l0x, l1x, l2x, l3x, l0y, l1y, l2y, l3y; double d0x, d1x, d2x, d3x, d0y, d1y, d2y, d3y; w1x = x - 1./3.; w2x = x - 2./3.; w3x = x - 1.; w1y = y - 1./3.; w2y = y - 2./3.; w3y = y - 1.; l0x = (- 4.5) * w1x * w2x * w3x; l1x = ( 13.5) * x * w2x * w3x; l2x = (-13.5) * x * w1x * w3x; l3x = ( 4.5) * x * w1x * w2x; l0y = (- 4.5) * w1y * w2y * w3y; l1y = ( 13.5) * y * w2y * w3y; l2y = (-13.5) * y * w1y * w3y; l3y = ( 4.5) * y * w1y * w2y; d0x = -5.5 + ( 18. - 13.5 * x) * x; d1x = 9. + (-45. + 40.5 * x) * x; d2x = -4.5 + ( 36. - 40.5 * x) * x; d3x = 1. + (- 9. + 13.5 * x) * x; d0y = -5.5 + ( 18. - 13.5 * y) * y; d1y = 9. + (-45. + 40.5 * y) * y; d2y = -4.5 + ( 36. - 40.5 * y) * y; d3y = 1. + (- 9. + 13.5 * y) * y; dshape( 0,0) = d0x * l0y; dshape( 0,1) = l0x * d0y; dshape( 1,0) = d3x * l0y; dshape( 1,1) = l3x * d0y; dshape( 2,0) = d3x * l3y; dshape( 2,1) = l3x * d3y; dshape( 3,0) = d0x * l3y; dshape( 3,1) = l0x * d3y; dshape( 4,0) = d1x * l0y; dshape( 4,1) = l1x * d0y; dshape( 5,0) = d2x * l0y; dshape( 5,1) = l2x * d0y; dshape( 6,0) = d3x * l1y; dshape( 6,1) = l3x * d1y; dshape( 7,0) = d3x * l2y; dshape( 7,1) = l3x * d2y; dshape( 8,0) = d2x * l3y; dshape( 8,1) = l2x * d3y; dshape( 9,0) = d1x * l3y; dshape( 9,1) = l1x * d3y; dshape(10,0) = d0x * l2y; dshape(10,1) = l0x * d2y; dshape(11,0) = d0x * l1y; dshape(11,1) = l0x * d1y; dshape(12,0) = d1x * l1y; dshape(12,1) = l1x * d1y; dshape(13,0) = d2x * l1y; dshape(13,1) = l2x * d1y; dshape(14,0) = d1x * l2y; dshape(14,1) = l1x * d2y; dshape(15,0) = d2x * l2y; dshape(15,1) = l2x * d2y; } void BiCubic2DFiniteElement::CalcHessian( const IntegrationPoint &ip, DenseMatrix &h) const { double x = ip.x, y = ip.y; double w1x, w2x, w3x, w1y, w2y, w3y; double l0x, l1x, l2x, l3x, l0y, l1y, l2y, l3y; double d0x, d1x, d2x, d3x, d0y, d1y, d2y, d3y; double h0x, h1x, h2x, h3x, h0y, h1y, h2y, h3y; w1x = x - 1./3.; w2x = x - 2./3.; w3x = x - 1.; w1y = y - 1./3.; w2y = y - 2./3.; w3y = y - 1.; l0x = (- 4.5) * w1x * w2x * w3x; l1x = ( 13.5) * x * w2x * w3x; l2x = (-13.5) * x * w1x * w3x; l3x = ( 4.5) * x * w1x * w2x; l0y = (- 4.5) * w1y * w2y * w3y; l1y = ( 13.5) * y * w2y * w3y; l2y = (-13.5) * y * w1y * w3y; l3y = ( 4.5) * y * w1y * w2y; d0x = -5.5 + ( 18. - 13.5 * x) * x; d1x = 9. + (-45. + 40.5 * x) * x; d2x = -4.5 + ( 36. - 40.5 * x) * x; d3x = 1. + (- 9. + 13.5 * x) * x; d0y = -5.5 + ( 18. - 13.5 * y) * y; d1y = 9. + (-45. + 40.5 * y) * y; d2y = -4.5 + ( 36. - 40.5 * y) * y; d3y = 1. + (- 9. + 13.5 * y) * y; h0x = -27. * x + 18.; h1x = 81. * x - 45.; h2x = -81. * x + 36.; h3x = 27. * x - 9.; h0y = -27. * y + 18.; h1y = 81. * y - 45.; h2y = -81. * y + 36.; h3y = 27. * y - 9.; h( 0,0) = h0x * l0y; h( 0,1) = d0x * d0y; h( 0,2) = l0x * h0y; h( 1,0) = h3x * l0y; h( 1,1) = d3x * d0y; h( 1,2) = l3x * h0y; h( 2,0) = h3x * l3y; h( 2,1) = d3x * d3y; h( 2,2) = l3x * h3y; h( 3,0) = h0x * l3y; h( 3,1) = d0x * d3y; h( 3,2) = l0x * h3y; h( 4,0) = h1x * l0y; h( 4,1) = d1x * d0y; h( 4,2) = l1x * h0y; h( 5,0) = h2x * l0y; h( 5,1) = d2x * d0y; h( 5,2) = l2x * h0y; h( 6,0) = h3x * l1y; h( 6,1) = d3x * d1y; h( 6,2) = l3x * h1y; h( 7,0) = h3x * l2y; h( 7,1) = d3x * d2y; h( 7,2) = l3x * h2y; h( 8,0) = h2x * l3y; h( 8,1) = d2x * d3y; h( 8,2) = l2x * h3y; h( 9,0) = h1x * l3y; h( 9,1) = d1x * d3y; h( 9,2) = l1x * h3y; h(10,0) = h0x * l2y; h(10,1) = d0x * d2y; h(10,2) = l0x * h2y; h(11,0) = h0x * l1y; h(11,1) = d0x * d1y; h(11,2) = l0x * h1y; h(12,0) = h1x * l1y; h(12,1) = d1x * d1y; h(12,2) = l1x * h1y; h(13,0) = h2x * l1y; h(13,1) = d2x * d1y; h(13,2) = l2x * h1y; h(14,0) = h1x * l2y; h(14,1) = d1x * d2y; h(14,2) = l1x * h2y; h(15,0) = h2x * l2y; h(15,1) = d2x * d2y; h(15,2) = l2x * h2y; } Cubic1DFiniteElement::Cubic1DFiniteElement() : NodalFiniteElement(1, Geometry::SEGMENT, 4, 3) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(2).x = 0.33333333333333333333; Nodes.IntPoint(3).x = 0.66666666666666666667; } void Cubic1DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = ip.x; double l1 = x, l2 = (1.0-x), l3 = (0.33333333333333333333-x), l4 = (0.66666666666666666667-x); shape(0) = 4.5 * l2 * l3 * l4; shape(1) = 4.5 * l1 * l3 * l4; shape(2) = 13.5 * l1 * l2 * l4; shape(3) = -13.5 * l1 * l2 * l3; } void Cubic1DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double x = ip.x; dshape(0,0) = -5.5 + x * (18. - 13.5 * x); dshape(1,0) = 1. - x * (9. - 13.5 * x); dshape(2,0) = 9. - x * (45. - 40.5 * x); dshape(3,0) = -4.5 + x * (36. - 40.5 * x); } Cubic2DFiniteElement::Cubic2DFiniteElement() : NodalFiniteElement(2, Geometry::TRIANGLE, 10, 3) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(3).x = 0.33333333333333333333; Nodes.IntPoint(3).y = 0.0; Nodes.IntPoint(4).x = 0.66666666666666666667; Nodes.IntPoint(4).y = 0.0; Nodes.IntPoint(5).x = 0.66666666666666666667; Nodes.IntPoint(5).y = 0.33333333333333333333; Nodes.IntPoint(6).x = 0.33333333333333333333; Nodes.IntPoint(6).y = 0.66666666666666666667; Nodes.IntPoint(7).x = 0.0; Nodes.IntPoint(7).y = 0.66666666666666666667; Nodes.IntPoint(8).x = 0.0; Nodes.IntPoint(8).y = 0.33333333333333333333; Nodes.IntPoint(9).x = 0.33333333333333333333; Nodes.IntPoint(9).y = 0.33333333333333333333; } void Cubic2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = ip.x, y = ip.y; double l1 = (-1. + x + y), lx = (-1. + 3.*x), ly = (-1. + 3.*y); shape(0) = -0.5*l1*(3.*l1 + 1.)*(3.*l1 + 2.); shape(1) = 0.5*x*(lx - 1.)*lx; shape(2) = 0.5*y*(-1. + ly)*ly; shape(3) = 4.5*x*l1*(3.*l1 + 1.); shape(4) = -4.5*x*lx*l1; shape(5) = 4.5*x*lx*y; shape(6) = 4.5*x*y*ly; shape(7) = -4.5*y*l1*ly; shape(8) = 4.5*y*l1*(1. + 3.*l1); shape(9) = -27.*x*y*l1; } void Cubic2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double x = ip.x, y = ip.y; dshape(0,0) = 0.5*(-11. + 36.*y - 9.*(x*(-4. + 3.*x) + 6.*x*y + 3.*y*y)); dshape(1,0) = 1. + 4.5*x*(-2. + 3.*x); dshape(2,0) = 0.; dshape(3,0) = 4.5*(2. + 9.*x*x - 5.*y + 3.*y*y + 2.*x*(-5. + 6.*y)); dshape(4,0) = -4.5*(1. - 1.*y + x*(-8. + 9.*x + 6.*y)); dshape(5,0) = 4.5*(-1. + 6.*x)*y; dshape(6,0) = 4.5*y*(-1. + 3.*y); dshape(7,0) = 4.5*(1. - 3.*y)*y; dshape(8,0) = 4.5*y*(-5. + 6.*x + 6.*y); dshape(9,0) = -27.*y*(-1. + 2.*x + y); dshape(0,1) = 0.5*(-11. + 36.*y - 9.*(x*(-4. + 3.*x) + 6.*x*y + 3.*y*y)); dshape(1,1) = 0.; dshape(2,1) = 1. + 4.5*y*(-2. + 3.*y); dshape(3,1) = 4.5*x*(-5. + 6.*x + 6.*y); dshape(4,1) = 4.5*(1. - 3.*x)*x; dshape(5,1) = 4.5*x*(-1. + 3.*x); dshape(6,1) = 4.5*x*(-1. + 6.*y); dshape(7,1) = -4.5*(1. + x*(-1. + 6.*y) + y*(-8. + 9.*y)); dshape(8,1) = 4.5*(2. + 3.*x*x + y*(-10. + 9.*y) + x*(-5. + 12.*y)); dshape(9,1) = -27.*x*(-1. + x + 2.*y); } void Cubic2DFiniteElement::CalcHessian (const IntegrationPoint &ip, DenseMatrix &h) const { double x = ip.x, y = ip.y; h(0,0) = 18.-27.*(x+y); h(0,1) = 18.-27.*(x+y); h(0,2) = 18.-27.*(x+y); h(1,0) = -9.+27.*x; h(1,1) = 0.; h(1,2) = 0.; h(2,0) = 0.; h(2,1) = 0.; h(2,2) = -9.+27.*y; h(3,0) = -45.+81.*x+54.*y; h(3,1) = -22.5+54.*x+27.*y; h(3,2) = 27.*x; h(4,0) = 36.-81.*x-27.*y; h(4,1) = 4.5-27.*x; h(4,2) = 0.; h(5,0) = 27.*y; h(5,1) = -4.5+27.*x; h(5,2) = 0.; h(6,0) = 0.; h(6,1) = -4.5+27.*y; h(6,2) = 27.*x; h(7,0) = 0.; h(7,1) = 4.5-27.*y; h(7,2) = 36.-27.*x-81.*y; h(8,0) = 27.*y; h(8,1) = -22.5+27.*x+54.*y; h(8,2) = -45.+54.*x+81.*y; h(9,0) = -54.*y; h(9,1) = 27.-54.*(x+y); h(9,2) = -54.*x; } Cubic3DFiniteElement::Cubic3DFiniteElement() : NodalFiniteElement(3, Geometry::TETRAHEDRON, 20, 3) { Nodes.IntPoint(0).x = 0; Nodes.IntPoint(0).y = 0; Nodes.IntPoint(0).z = 0; Nodes.IntPoint(1).x = 1.; Nodes.IntPoint(1).y = 0; Nodes.IntPoint(1).z = 0; Nodes.IntPoint(2).x = 0; Nodes.IntPoint(2).y = 1.; Nodes.IntPoint(2).z = 0; Nodes.IntPoint(3).x = 0; Nodes.IntPoint(3).y = 0; Nodes.IntPoint(3).z = 1.; Nodes.IntPoint(4).x = 0.3333333333333333333333333333; Nodes.IntPoint(4).y = 0; Nodes.IntPoint(4).z = 0; Nodes.IntPoint(5).x = 0.6666666666666666666666666667; Nodes.IntPoint(5).y = 0; Nodes.IntPoint(5).z = 0; Nodes.IntPoint(6).x = 0; Nodes.IntPoint(6).y = 0.3333333333333333333333333333; Nodes.IntPoint(6).z = 0; Nodes.IntPoint(7).x = 0; Nodes.IntPoint(7).y = 0.6666666666666666666666666667; Nodes.IntPoint(7).z = 0; Nodes.IntPoint(8).x = 0; Nodes.IntPoint(8).y = 0; Nodes.IntPoint(8).z = 0.3333333333333333333333333333; Nodes.IntPoint(9).x = 0; Nodes.IntPoint(9).y = 0; Nodes.IntPoint(9).z = 0.6666666666666666666666666667; Nodes.IntPoint(10).x = 0.6666666666666666666666666667; Nodes.IntPoint(10).y = 0.3333333333333333333333333333; Nodes.IntPoint(10).z = 0; Nodes.IntPoint(11).x = 0.3333333333333333333333333333; Nodes.IntPoint(11).y = 0.6666666666666666666666666667; Nodes.IntPoint(11).z = 0; Nodes.IntPoint(12).x = 0.6666666666666666666666666667; Nodes.IntPoint(12).y = 0; Nodes.IntPoint(12).z = 0.3333333333333333333333333333; Nodes.IntPoint(13).x = 0.3333333333333333333333333333; Nodes.IntPoint(13).y = 0; Nodes.IntPoint(13).z = 0.6666666666666666666666666667; Nodes.IntPoint(14).x = 0; Nodes.IntPoint(14).y = 0.6666666666666666666666666667; Nodes.IntPoint(14).z = 0.3333333333333333333333333333; Nodes.IntPoint(15).x = 0; Nodes.IntPoint(15).y = 0.3333333333333333333333333333; Nodes.IntPoint(15).z = 0.6666666666666666666666666667; Nodes.IntPoint(16).x = 0.3333333333333333333333333333; Nodes.IntPoint(16).y = 0.3333333333333333333333333333; Nodes.IntPoint(16).z = 0.3333333333333333333333333333; Nodes.IntPoint(17).x = 0; Nodes.IntPoint(17).y = 0.3333333333333333333333333333; Nodes.IntPoint(17).z = 0.3333333333333333333333333333; Nodes.IntPoint(18).x = 0.3333333333333333333333333333; Nodes.IntPoint(18).y = 0; Nodes.IntPoint(18).z = 0.3333333333333333333333333333; Nodes.IntPoint(19).x = 0.3333333333333333333333333333; Nodes.IntPoint(19).y = 0.3333333333333333333333333333; Nodes.IntPoint(19).z = 0; } void Cubic3DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = ip.x, y = ip.y, z = ip.z; shape(0) = -((-1 + x + y + z)*(-2 + 3*x + 3*y + 3*z)* (-1 + 3*x + 3*y + 3*z))/2.; shape(4) = (9*x*(-1 + x + y + z)*(-2 + 3*x + 3*y + 3*z))/2.; shape(5) = (-9*x*(-1 + 3*x)*(-1 + x + y + z))/2.; shape(1) = (x*(2 + 9*(-1 + x)*x))/2.; shape(6) = (9*y*(-1 + x + y + z)*(-2 + 3*x + 3*y + 3*z))/2.; shape(19) = -27*x*y*(-1 + x + y + z); shape(10) = (9*x*(-1 + 3*x)*y)/2.; shape(7) = (-9*y*(-1 + 3*y)*(-1 + x + y + z))/2.; shape(11) = (9*x*y*(-1 + 3*y))/2.; shape(2) = (y*(2 + 9*(-1 + y)*y))/2.; shape(8) = (9*z*(-1 + x + y + z)*(-2 + 3*x + 3*y + 3*z))/2.; shape(18) = -27*x*z*(-1 + x + y + z); shape(12) = (9*x*(-1 + 3*x)*z)/2.; shape(17) = -27*y*z*(-1 + x + y + z); shape(16) = 27*x*y*z; shape(14) = (9*y*(-1 + 3*y)*z)/2.; shape(9) = (-9*z*(-1 + x + y + z)*(-1 + 3*z))/2.; shape(13) = (9*x*z*(-1 + 3*z))/2.; shape(15) = (9*y*z*(-1 + 3*z))/2.; shape(3) = (z*(2 + 9*(-1 + z)*z))/2.; } void Cubic3DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double x = ip.x, y = ip.y, z = ip.z; dshape(0,0) = (-11 + 36*y + 36*z - 9*(3*pow(x,2) + 3*pow(y + z,2) + x*(-4 + 6*y + 6*z)))/2.; dshape(0,1) = (-11 + 36*y + 36*z - 9*(3*pow(x,2) + 3*pow(y + z,2) + x*(-4 + 6*y + 6*z)))/2.; dshape(0,2) = (-11 + 36*y + 36*z - 9*(3*pow(x,2) + 3*pow(y + z,2) + x*(-4 + 6*y + 6*z)))/2.; dshape(4,0) = (9*(9*pow(x,2) + (-1 + y + z)*(-2 + 3*y + 3*z) + 2*x*(-5 + 6*y + 6*z)))/2.; dshape(4,1) = (9*x*(-5 + 6*x + 6*y + 6*z))/2.; dshape(4,2) = (9*x*(-5 + 6*x + 6*y + 6*z))/2.; dshape(5,0) = (-9*(1 - y - z + x*(-8 + 9*x + 6*y + 6*z)))/2.; dshape(5,1) = (9*(1 - 3*x)*x)/2.; dshape(5,2) = (9*(1 - 3*x)*x)/2.; dshape(1,0) = 1 + (9*x*(-2 + 3*x))/2.; dshape(1,1) = 0; dshape(1,2) = 0; dshape(6,0) = (9*y*(-5 + 6*x + 6*y + 6*z))/2.; dshape(6,1) = (9*(2 + 3*pow(x,2) - 10*y - 5*z + 3*(y + z)*(3*y + z) + x*(-5 + 12*y + 6*z)))/2.; dshape(6,2) = (9*y*(-5 + 6*x + 6*y + 6*z))/2.; dshape(19,0) = -27*y*(-1 + 2*x + y + z); dshape(19,1) = -27*x*(-1 + x + 2*y + z); dshape(19,2) = -27*x*y; dshape(10,0) = (9*(-1 + 6*x)*y)/2.; dshape(10,1) = (9*x*(-1 + 3*x))/2.; dshape(10,2) = 0; dshape(7,0) = (9*(1 - 3*y)*y)/2.; dshape(7,1) = (-9*(1 + x*(-1 + 6*y) - z + y*(-8 + 9*y + 6*z)))/2.; dshape(7,2) = (9*(1 - 3*y)*y)/2.; dshape(11,0) = (9*y*(-1 + 3*y))/2.; dshape(11,1) = (9*x*(-1 + 6*y))/2.; dshape(11,2) = 0; dshape(2,0) = 0; dshape(2,1) = 1 + (9*y*(-2 + 3*y))/2.; dshape(2,2) = 0; dshape(8,0) = (9*z*(-5 + 6*x + 6*y + 6*z))/2.; dshape(8,1) = (9*z*(-5 + 6*x + 6*y + 6*z))/2.; dshape(8,2) = (9*(2 + 3*pow(x,2) - 5*y - 10*z + 3*(y + z)*(y + 3*z) + x*(-5 + 6*y + 12*z)))/2.; dshape(18,0) = -27*z*(-1 + 2*x + y + z); dshape(18,1) = -27*x*z; dshape(18,2) = -27*x*(-1 + x + y + 2*z); dshape(12,0) = (9*(-1 + 6*x)*z)/2.; dshape(12,1) = 0; dshape(12,2) = (9*x*(-1 + 3*x))/2.; dshape(17,0) = -27*y*z; dshape(17,1) = -27*z*(-1 + x + 2*y + z); dshape(17,2) = -27*y*(-1 + x + y + 2*z); dshape(16,0) = 27*y*z; dshape(16,1) = 27*x*z; dshape(16,2) = 27*x*y; dshape(14,0) = 0; dshape(14,1) = (9*(-1 + 6*y)*z)/2.; dshape(14,2) = (9*y*(-1 + 3*y))/2.; dshape(9,0) = (9*(1 - 3*z)*z)/2.; dshape(9,1) = (9*(1 - 3*z)*z)/2.; dshape(9,2) = (9*(-1 + x + y + 8*z - 6*(x + y)*z - 9*pow(z,2)))/2.; dshape(13,0) = (9*z*(-1 + 3*z))/2.; dshape(13,1) = 0; dshape(13,2) = (9*x*(-1 + 6*z))/2.; dshape(15,0) = 0; dshape(15,1) = (9*z*(-1 + 3*z))/2.; dshape(15,2) = (9*y*(-1 + 6*z))/2.; dshape(3,0) = 0; dshape(3,1) = 0; dshape(3,2) = 1 + (9*z*(-2 + 3*z))/2.; } P0TriangleFiniteElement::P0TriangleFiniteElement() : NodalFiniteElement(2, Geometry::TRIANGLE, 1, 0) { Nodes.IntPoint(0).x = 0.333333333333333333; Nodes.IntPoint(0).y = 0.333333333333333333; } void P0TriangleFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1.0; } void P0TriangleFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = 0.0; dshape(0,1) = 0.0; } P0QuadFiniteElement::P0QuadFiniteElement() : NodalFiniteElement(2, Geometry::SQUARE, 1, 0, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.5; Nodes.IntPoint(0).y = 0.5; } void P0QuadFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1.0; } void P0QuadFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = 0.0; dshape(0,1) = 0.0; } Linear3DFiniteElement::Linear3DFiniteElement() : NodalFiniteElement(3, Geometry::TETRAHEDRON, 4, 1) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(0).z = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(1).z = 0.0; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(2).z = 0.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 0.0; Nodes.IntPoint(3).z = 1.0; } void Linear3DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1. - ip.x - ip.y - ip.z; shape(1) = ip.x; shape(2) = ip.y; shape(3) = ip.z; } void Linear3DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { if (dshape.Height() == 4) { double *A = &dshape(0,0); A[0] = -1.; A[4] = -1.; A[8] = -1.; A[1] = 1.; A[5] = 0.; A[9] = 0.; A[2] = 0.; A[6] = 1.; A[10] = 0.; A[3] = 0.; A[7] = 0.; A[11] = 1.; } else { dshape(0,0) = -1.; dshape(0,1) = -1.; dshape(0,2) = -1.; dshape(1,0) = 1.; dshape(1,1) = 0.; dshape(1,2) = 0.; dshape(2,0) = 0.; dshape(2,1) = 1.; dshape(2,2) = 0.; dshape(3,0) = 0.; dshape(3,1) = 0.; dshape(3,2) = 1.; } } void Linear3DFiniteElement::GetFaceDofs (int face, int **dofs, int *ndofs) const { static int face_dofs[4][3] = {{1, 2, 3}, {0, 2, 3}, {0, 1, 3}, {0, 1, 2}}; *ndofs = 3; *dofs = face_dofs[face]; } Quadratic3DFiniteElement::Quadratic3DFiniteElement() : NodalFiniteElement(3, Geometry::TETRAHEDRON, 10, 2) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(0).z = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(1).z = 0.0; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(2).z = 0.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 0.0; Nodes.IntPoint(3).z = 1.0; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = 0.0; Nodes.IntPoint(4).z = 0.0; Nodes.IntPoint(5).x = 0.0; Nodes.IntPoint(5).y = 0.5; Nodes.IntPoint(5).z = 0.0; Nodes.IntPoint(6).x = 0.0; Nodes.IntPoint(6).y = 0.0; Nodes.IntPoint(6).z = 0.5; Nodes.IntPoint(7).x = 0.5; Nodes.IntPoint(7).y = 0.5; Nodes.IntPoint(7).z = 0.0; Nodes.IntPoint(8).x = 0.5; Nodes.IntPoint(8).y = 0.0; Nodes.IntPoint(8).z = 0.5; Nodes.IntPoint(9).x = 0.0; Nodes.IntPoint(9).y = 0.5; Nodes.IntPoint(9).z = 0.5; } void Quadratic3DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double L0, L1, L2, L3; L0 = 1. - ip.x - ip.y - ip.z; L1 = ip.x; L2 = ip.y; L3 = ip.z; shape(0) = L0 * ( 2.0 * L0 - 1.0 ); shape(1) = L1 * ( 2.0 * L1 - 1.0 ); shape(2) = L2 * ( 2.0 * L2 - 1.0 ); shape(3) = L3 * ( 2.0 * L3 - 1.0 ); shape(4) = 4.0 * L0 * L1; shape(5) = 4.0 * L0 * L2; shape(6) = 4.0 * L0 * L3; shape(7) = 4.0 * L1 * L2; shape(8) = 4.0 * L1 * L3; shape(9) = 4.0 * L2 * L3; } void Quadratic3DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double x, y, z, L0; x = ip.x; y = ip.y; z = ip.z; L0 = 1.0 - x - y - z; dshape(0,0) = dshape(0,1) = dshape(0,2) = 1.0 - 4.0 * L0; dshape(1,0) = -1.0 + 4.0 * x; dshape(1,1) = 0.0; dshape(1,2) = 0.0; dshape(2,0) = 0.0; dshape(2,1) = -1.0 + 4.0 * y; dshape(2,2) = 0.0; dshape(3,0) = dshape(3,1) = 0.0; dshape(3,2) = -1.0 + 4.0 * z; dshape(4,0) = 4.0 * (L0 - x); dshape(4,1) = dshape(4,2) = -4.0 * x; dshape(5,0) = dshape(5,2) = -4.0 * y; dshape(5,1) = 4.0 * (L0 - y); dshape(6,0) = dshape(6,1) = -4.0 * z; dshape(6,2) = 4.0 * (L0 - z); dshape(7,0) = 4.0 * y; dshape(7,1) = 4.0 * x; dshape(7,2) = 0.0; dshape(8,0) = 4.0 * z; dshape(8,1) = 0.0; dshape(8,2) = 4.0 * x; dshape(9,0) = 0.0; dshape(9,1) = 4.0 * z; dshape(9,2) = 4.0 * y; } TriLinear3DFiniteElement::TriLinear3DFiniteElement() : NodalFiniteElement(3, Geometry::CUBE, 8, 1, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(0).z = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(1).z = 0.0; Nodes.IntPoint(2).x = 1.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(2).z = 0.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 1.0; Nodes.IntPoint(3).z = 0.0; Nodes.IntPoint(4).x = 0.0; Nodes.IntPoint(4).y = 0.0; Nodes.IntPoint(4).z = 1.0; Nodes.IntPoint(5).x = 1.0; Nodes.IntPoint(5).y = 0.0; Nodes.IntPoint(5).z = 1.0; Nodes.IntPoint(6).x = 1.0; Nodes.IntPoint(6).y = 1.0; Nodes.IntPoint(6).z = 1.0; Nodes.IntPoint(7).x = 0.0; Nodes.IntPoint(7).y = 1.0; Nodes.IntPoint(7).z = 1.0; } void TriLinear3DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = ip.x, y = ip.y, z = ip.z; double ox = 1.-x, oy = 1.-y, oz = 1.-z; shape(0) = ox * oy * oz; shape(1) = x * oy * oz; shape(2) = x * y * oz; shape(3) = ox * y * oz; shape(4) = ox * oy * z; shape(5) = x * oy * z; shape(6) = x * y * z; shape(7) = ox * y * z; } void TriLinear3DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double x = ip.x, y = ip.y, z = ip.z; double ox = 1.-x, oy = 1.-y, oz = 1.-z; dshape(0,0) = - oy * oz; dshape(0,1) = - ox * oz; dshape(0,2) = - ox * oy; dshape(1,0) = oy * oz; dshape(1,1) = - x * oz; dshape(1,2) = - x * oy; dshape(2,0) = y * oz; dshape(2,1) = x * oz; dshape(2,2) = - x * y; dshape(3,0) = - y * oz; dshape(3,1) = ox * oz; dshape(3,2) = - ox * y; dshape(4,0) = - oy * z; dshape(4,1) = - ox * z; dshape(4,2) = ox * oy; dshape(5,0) = oy * z; dshape(5,1) = - x * z; dshape(5,2) = x * oy; dshape(6,0) = y * z; dshape(6,1) = x * z; dshape(6,2) = x * y; dshape(7,0) = - y * z; dshape(7,1) = ox * z; dshape(7,2) = ox * y; } P0SegmentFiniteElement::P0SegmentFiniteElement(int Ord) : NodalFiniteElement(1, Geometry::SEGMENT, 1, Ord) // default Ord = 0 { Nodes.IntPoint(0).x = 0.5; } void P0SegmentFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1.0; } void P0SegmentFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = 0.0; } CrouzeixRaviartFiniteElement::CrouzeixRaviartFiniteElement() : NodalFiniteElement(2, Geometry::TRIANGLE, 3, 1) { Nodes.IntPoint(0).x = 0.5; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 0.5; Nodes.IntPoint(1).y = 0.5; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 0.5; } void CrouzeixRaviartFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1.0 - 2.0 * ip.y; shape(1) = -1.0 + 2.0 * ( ip.x + ip.y ); shape(2) = 1.0 - 2.0 * ip.x; } void CrouzeixRaviartFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = 0.0; dshape(0,1) = -2.0; dshape(1,0) = 2.0; dshape(1,1) = 2.0; dshape(2,0) = -2.0; dshape(2,1) = 0.0; } CrouzeixRaviartQuadFiniteElement::CrouzeixRaviartQuadFiniteElement() // the FunctionSpace should be rotated (45 degrees) Q_1 // i.e. the span of { 1, x, y, x^2 - y^2 } : NodalFiniteElement(2, Geometry::SQUARE, 4, 2, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.5; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.5; Nodes.IntPoint(2).x = 0.5; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 0.5; } void CrouzeixRaviartQuadFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const double l1 = ip.x+ip.y-0.5, l2 = 1.-l1, l3 = ip.x-ip.y+0.5, l4 = 1.-l3; shape(0) = l2 * l3; shape(1) = l1 * l3; shape(2) = l1 * l4; shape(3) = l2 * l4; } void CrouzeixRaviartQuadFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const double x2 = 2.*ip.x, y2 = 2.*ip.y; dshape(0,0) = 1. - x2; dshape(0,1) = -2. + y2; dshape(1,0) = x2; dshape(1,1) = 1. - y2; dshape(2,0) = 1. - x2; dshape(2,1) = y2; dshape(3,0) = -2. + x2; dshape(3,1) = 1. - y2; } RT0TriangleFiniteElement::RT0TriangleFiniteElement() : VectorFiniteElement(2, Geometry::TRIANGLE, 3, 1, H_DIV) { Nodes.IntPoint(0).x = 0.5; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 0.5; Nodes.IntPoint(1).y = 0.5; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 0.5; } void RT0TriangleFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x = ip.x, y = ip.y; shape(0,0) = x; shape(0,1) = y - 1.; shape(1,0) = x; shape(1,1) = y; shape(2,0) = x - 1.; shape(2,1) = y; } void RT0TriangleFiniteElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { divshape(0) = 2.; divshape(1) = 2.; divshape(2) = 2.; } const double RT0TriangleFiniteElement::nk[3][2] = { {0, -1}, {1, 1}, {-1, 0} }; void RT0TriangleFiniteElement::GetLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I) const { int k, j; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG for (k = 0; k < 3; k++) { CalcVShape (Nodes.IntPoint(k), vshape); for (j = 0; j < 3; j++) { double d = vshape(j,0)*nk[k][0]+vshape(j,1)*nk[k][1]; if (j == k) { d -= 1.0; } if (fabs(d) > 1.0e-12) { mfem::err << "RT0TriangleFiniteElement::GetLocalInterpolation (...)\n" " k = " << k << ", j = " << j << ", d = " << d << endl; mfem_error(); } } } #endif IntegrationPoint ip; ip.x = ip.y = 0.0; Trans.SetIntPoint (&ip); // Trans must be linear // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); double vk[2]; Vector xk (vk, 2); for (k = 0; k < 3; k++) { Trans.Transform (Nodes.IntPoint (k), xk); ip.x = vk[0]; ip.y = vk[1]; CalcVShape (ip, vshape); // vk = |J| J^{-t} nk vk[0] = Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]; vk[1] = Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]; for (j = 0; j < 3; j++) if (fabs (I(k,j) = vshape(j,0)*vk[0]+vshape(j,1)*vk[1]) < 1.0e-12) { I(k,j) = 0.0; } } } void RT0TriangleFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[2]; Vector xk (vk, 2); #ifdef MFEM_THREAD_SAFE DenseMatrix Jinv(dim); #endif for (int k = 0; k < 3; k++) { Trans.SetIntPoint (&Nodes.IntPoint (k)); // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); vc.Eval (xk, Trans, Nodes.IntPoint (k)); // xk^t |J| J^{-t} nk dofs(k) = (vk[0] * ( Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1] ) + vk[1] * ( Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1] )); } } RT0QuadFiniteElement::RT0QuadFiniteElement() : VectorFiniteElement(2, Geometry::SQUARE, 4, 1, H_DIV, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.5; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.5; Nodes.IntPoint(2).x = 0.5; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 0.5; } void RT0QuadFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x = ip.x, y = ip.y; shape(0,0) = 0; shape(0,1) = y - 1.; shape(1,0) = x; shape(1,1) = 0; shape(2,0) = 0; shape(2,1) = y; shape(3,0) = x - 1.; shape(3,1) = 0; } void RT0QuadFiniteElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { divshape(0) = 1.; divshape(1) = 1.; divshape(2) = 1.; divshape(3) = 1.; } const double RT0QuadFiniteElement::nk[4][2] = { {0, -1}, {1, 0}, {0, 1}, {-1, 0} }; void RT0QuadFiniteElement::GetLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I) const { int k, j; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG for (k = 0; k < 4; k++) { CalcVShape (Nodes.IntPoint(k), vshape); for (j = 0; j < 4; j++) { double d = vshape(j,0)*nk[k][0]+vshape(j,1)*nk[k][1]; if (j == k) { d -= 1.0; } if (fabs(d) > 1.0e-12) { mfem::err << "RT0QuadFiniteElement::GetLocalInterpolation (...)\n" " k = " << k << ", j = " << j << ", d = " << d << endl; mfem_error(); } } } #endif IntegrationPoint ip; ip.x = ip.y = 0.0; Trans.SetIntPoint (&ip); // Trans must be linear (more to have embedding?) // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); double vk[2]; Vector xk (vk, 2); for (k = 0; k < 4; k++) { Trans.Transform (Nodes.IntPoint (k), xk); ip.x = vk[0]; ip.y = vk[1]; CalcVShape (ip, vshape); // vk = |J| J^{-t} nk vk[0] = Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]; vk[1] = Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]; for (j = 0; j < 4; j++) if (fabs (I(k,j) = vshape(j,0)*vk[0]+vshape(j,1)*vk[1]) < 1.0e-12) { I(k,j) = 0.0; } } } void RT0QuadFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[2]; Vector xk (vk, 2); #ifdef MFEM_THREAD_SAFE DenseMatrix Jinv(dim); #endif for (int k = 0; k < 4; k++) { Trans.SetIntPoint (&Nodes.IntPoint (k)); // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); vc.Eval (xk, Trans, Nodes.IntPoint (k)); // xk^t |J| J^{-t} nk dofs(k) = (vk[0] * ( Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1] ) + vk[1] * ( Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1] )); } } RT1TriangleFiniteElement::RT1TriangleFiniteElement() : VectorFiniteElement(2, Geometry::TRIANGLE, 8, 2, H_DIV) { Nodes.IntPoint(0).x = 0.33333333333333333333; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 0.66666666666666666667; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 0.66666666666666666667; Nodes.IntPoint(2).y = 0.33333333333333333333; Nodes.IntPoint(3).x = 0.33333333333333333333; Nodes.IntPoint(3).y = 0.66666666666666666667; Nodes.IntPoint(4).x = 0.0; Nodes.IntPoint(4).y = 0.66666666666666666667; Nodes.IntPoint(5).x = 0.0; Nodes.IntPoint(5).y = 0.33333333333333333333; Nodes.IntPoint(6).x = 0.33333333333333333333; Nodes.IntPoint(6).y = 0.33333333333333333333; Nodes.IntPoint(7).x = 0.33333333333333333333; Nodes.IntPoint(7).y = 0.33333333333333333333; } void RT1TriangleFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x = ip.x, y = ip.y; shape(0,0) = -2 * x * (-1 + x + 2 * y); shape(0,1) = -2 * (-1 + y) * (-1 + x + 2 * y); shape(1,0) = 2 * x * (x - y); shape(1,1) = 2 * (x - y) * (-1 + y); shape(2,0) = 2 * x * (-1 + 2 * x + y); shape(2,1) = 2 * y * (-1 + 2 * x + y); shape(3,0) = 2 * x * (-1 + x + 2 * y); shape(3,1) = 2 * y * (-1 + x + 2 * y); shape(4,0) = -2 * (-1 + x) * (x - y); shape(4,1) = 2 * y * (-x + y); shape(5,0) = -2 * (-1 + x) * (-1 + 2 * x + y); shape(5,1) = -2 * y * (-1 + 2 * x + y); shape(6,0) = -3 * x * (-2 + 2 * x + y); shape(6,1) = -3 * y * (-1 + 2 * x + y); shape(7,0) = -3 * x * (-1 + x + 2 * y); shape(7,1) = -3 * y * (-2 + x + 2 * y); } void RT1TriangleFiniteElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { double x = ip.x, y = ip.y; divshape(0) = -2 * (-4 + 3 * x + 6 * y); divshape(1) = 2 + 6 * x - 6 * y; divshape(2) = -4 + 12 * x + 6 * y; divshape(3) = -4 + 6 * x + 12 * y; divshape(4) = 2 - 6 * x + 6 * y; divshape(5) = -2 * (-4 + 6 * x + 3 * y); divshape(6) = -9 * (-1 + 2 * x + y); divshape(7) = -9 * (-1 + x + 2 * y); } const double RT1TriangleFiniteElement::nk[8][2] = { { 0,-1}, { 0,-1}, { 1, 1}, { 1, 1}, {-1, 0}, {-1, 0}, { 1, 0}, { 0, 1} }; void RT1TriangleFiniteElement::GetLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I) const { int k, j; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG for (k = 0; k < 8; k++) { CalcVShape (Nodes.IntPoint(k), vshape); for (j = 0; j < 8; j++) { double d = vshape(j,0)*nk[k][0]+vshape(j,1)*nk[k][1]; if (j == k) { d -= 1.0; } if (fabs(d) > 1.0e-12) { mfem::err << "RT1QuadFiniteElement::GetLocalInterpolation (...)\n" " k = " << k << ", j = " << j << ", d = " << d << endl; mfem_error(); } } } #endif IntegrationPoint ip; ip.x = ip.y = 0.0; Trans.SetIntPoint (&ip); // Trans must be linear (more to have embedding?) // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); double vk[2]; Vector xk (vk, 2); for (k = 0; k < 8; k++) { Trans.Transform (Nodes.IntPoint (k), xk); ip.x = vk[0]; ip.y = vk[1]; CalcVShape (ip, vshape); // vk = |J| J^{-t} nk vk[0] = Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]; vk[1] = Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]; for (j = 0; j < 8; j++) if (fabs (I(k,j) = vshape(j,0)*vk[0]+vshape(j,1)*vk[1]) < 1.0e-12) { I(k,j) = 0.0; } } } void RT1TriangleFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[2]; Vector xk (vk, 2); #ifdef MFEM_THREAD_SAFE DenseMatrix Jinv(dim); #endif for (int k = 0; k < 8; k++) { Trans.SetIntPoint (&Nodes.IntPoint (k)); // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); vc.Eval (xk, Trans, Nodes.IntPoint (k)); // xk^t |J| J^{-t} nk dofs(k) = (vk[0] * ( Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1] ) + vk[1] * ( Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1] )); dofs(k) *= 0.5; } } RT1QuadFiniteElement::RT1QuadFiniteElement() : VectorFiniteElement(2, Geometry::SQUARE, 12, 2, H_DIV, FunctionSpace::Qk) { // y = 0 Nodes.IntPoint(0).x = 1./3.; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 2./3.; Nodes.IntPoint(1).y = 0.0; // x = 1 Nodes.IntPoint(2).x = 1.0; Nodes.IntPoint(2).y = 1./3.; Nodes.IntPoint(3).x = 1.0; Nodes.IntPoint(3).y = 2./3.; // y = 1 Nodes.IntPoint(4).x = 2./3.; Nodes.IntPoint(4).y = 1.0; Nodes.IntPoint(5).x = 1./3.; Nodes.IntPoint(5).y = 1.0; // x = 0 Nodes.IntPoint(6).x = 0.0; Nodes.IntPoint(6).y = 2./3.; Nodes.IntPoint(7).x = 0.0; Nodes.IntPoint(7).y = 1./3.; // x = 0.5 (interior) Nodes.IntPoint(8).x = 0.5; Nodes.IntPoint(8).y = 1./3.; Nodes.IntPoint(9).x = 0.5; Nodes.IntPoint(9).y = 2./3.; // y = 0.5 (interior) Nodes.IntPoint(10).x = 1./3.; Nodes.IntPoint(10).y = 0.5; Nodes.IntPoint(11).x = 2./3.; Nodes.IntPoint(11).y = 0.5; } void RT1QuadFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x = ip.x, y = ip.y; // y = 0 shape(0,0) = 0; shape(0,1) = -( 1. - 3.*y + 2.*y*y)*( 2. - 3.*x); shape(1,0) = 0; shape(1,1) = -( 1. - 3.*y + 2.*y*y)*(-1. + 3.*x); // x = 1 shape(2,0) = (-x + 2.*x*x)*( 2. - 3.*y); shape(2,1) = 0; shape(3,0) = (-x + 2.*x*x)*(-1. + 3.*y); shape(3,1) = 0; // y = 1 shape(4,0) = 0; shape(4,1) = (-y + 2.*y*y)*(-1. + 3.*x); shape(5,0) = 0; shape(5,1) = (-y + 2.*y*y)*( 2. - 3.*x); // x = 0 shape(6,0) = -(1. - 3.*x + 2.*x*x)*(-1. + 3.*y); shape(6,1) = 0; shape(7,0) = -(1. - 3.*x + 2.*x*x)*( 2. - 3.*y); shape(7,1) = 0; // x = 0.5 (interior) shape(8,0) = (4.*x - 4.*x*x)*( 2. - 3.*y); shape(8,1) = 0; shape(9,0) = (4.*x - 4.*x*x)*(-1. + 3.*y); shape(9,1) = 0; // y = 0.5 (interior) shape(10,0) = 0; shape(10,1) = (4.*y - 4.*y*y)*( 2. - 3.*x); shape(11,0) = 0; shape(11,1) = (4.*y - 4.*y*y)*(-1. + 3.*x); } void RT1QuadFiniteElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { double x = ip.x, y = ip.y; divshape(0) = -(-3. + 4.*y)*( 2. - 3.*x); divshape(1) = -(-3. + 4.*y)*(-1. + 3.*x); divshape(2) = (-1. + 4.*x)*( 2. - 3.*y); divshape(3) = (-1. + 4.*x)*(-1. + 3.*y); divshape(4) = (-1. + 4.*y)*(-1. + 3.*x); divshape(5) = (-1. + 4.*y)*( 2. - 3.*x); divshape(6) = -(-3. + 4.*x)*(-1. + 3.*y); divshape(7) = -(-3. + 4.*x)*( 2. - 3.*y); divshape(8) = ( 4. - 8.*x)*( 2. - 3.*y); divshape(9) = ( 4. - 8.*x)*(-1. + 3.*y); divshape(10) = ( 4. - 8.*y)*( 2. - 3.*x); divshape(11) = ( 4. - 8.*y)*(-1. + 3.*x); } const double RT1QuadFiniteElement::nk[12][2] = { // y = 0 {0,-1}, {0,-1}, // X = 1 {1, 0}, {1, 0}, // y = 1 {0, 1}, {0, 1}, // x = 0 {-1,0}, {-1,0}, // x = 0.5 (interior) {1, 0}, {1, 0}, // y = 0.5 (interior) {0, 1}, {0, 1} }; void RT1QuadFiniteElement::GetLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I) const { int k, j; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG for (k = 0; k < 12; k++) { CalcVShape (Nodes.IntPoint(k), vshape); for (j = 0; j < 12; j++) { double d = vshape(j,0)*nk[k][0]+vshape(j,1)*nk[k][1]; if (j == k) { d -= 1.0; } if (fabs(d) > 1.0e-12) { mfem::err << "RT1QuadFiniteElement::GetLocalInterpolation (...)\n" " k = " << k << ", j = " << j << ", d = " << d << endl; mfem_error(); } } } #endif IntegrationPoint ip; ip.x = ip.y = 0.0; Trans.SetIntPoint (&ip); // Trans must be linear (more to have embedding?) // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); double vk[2]; Vector xk (vk, 2); for (k = 0; k < 12; k++) { Trans.Transform (Nodes.IntPoint (k), xk); ip.x = vk[0]; ip.y = vk[1]; CalcVShape (ip, vshape); // vk = |J| J^{-t} nk vk[0] = Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]; vk[1] = Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]; for (j = 0; j < 12; j++) if (fabs (I(k,j) = vshape(j,0)*vk[0]+vshape(j,1)*vk[1]) < 1.0e-12) { I(k,j) = 0.0; } } } void RT1QuadFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[2]; Vector xk (vk, 2); #ifdef MFEM_THREAD_SAFE DenseMatrix Jinv(dim); #endif for (int k = 0; k < 12; k++) { Trans.SetIntPoint (&Nodes.IntPoint (k)); // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); vc.Eval (xk, Trans, Nodes.IntPoint (k)); // xk^t |J| J^{-t} nk dofs(k) = (vk[0] * ( Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1] ) + vk[1] * ( Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1] )); } } const double RT2TriangleFiniteElement::M[15][15] = { { 0, -5.3237900077244501311, 5.3237900077244501311, 16.647580015448900262, 0, 24.442740046346700787, -16.647580015448900262, -12., -19.118950038622250656, -47.237900077244501311, 0, -34.414110069520051180, 12., 30.590320061795601049, 15.295160030897800524 }, { 0, 1.5, -1.5, -15., 0, 2.625, 15., 15., -4.125, 30., 0, -14.625, -15., -15., 10.5 }, { 0, -0.67620999227554986889, 0.67620999227554986889, 7.3524199845510997378, 0, -3.4427400463467007866, -7.3524199845510997378, -12., 4.1189500386222506555, -0.76209992275549868892, 0, 7.4141100695200511800, 12., -6.5903200617956010489, -3.2951600308978005244 }, { 0, 0, 1.5, 0, 0, 1.5, -11.471370023173350393, 0, 2.4713700231733503933, -11.471370023173350393, 0, 2.4713700231733503933, 15.295160030897800524, 0, -3.2951600308978005244 }, { 0, 0, 4.875, 0, 0, 4.875, -16.875, 0, -16.875, -16.875, 0, -16.875, 10.5, 36., 10.5 }, { 0, 0, 1.5, 0, 0, 1.5, 2.4713700231733503933, 0, -11.471370023173350393, 2.4713700231733503933, 0, -11.471370023173350393, -3.2951600308978005244, 0, 15.295160030897800524 }, { -0.67620999227554986889, 0, -3.4427400463467007866, 0, 7.3524199845510997378, 0.67620999227554986889, 7.4141100695200511800, 0, -0.76209992275549868892, 4.1189500386222506555, -12., -7.3524199845510997378, -3.2951600308978005244, -6.5903200617956010489, 12. }, { 1.5, 0, 2.625, 0, -15., -1.5, -14.625, 0, 30., -4.125, 15., 15., 10.5, -15., -15. }, { -5.3237900077244501311, 0, 24.442740046346700787, 0, 16.647580015448900262, 5.3237900077244501311, -34.414110069520051180, 0, -47.237900077244501311, -19.118950038622250656, -12., -16.647580015448900262, 15.295160030897800524, 30.590320061795601049, 12. }, { 0, 0, 18., 0, 0, 6., -42., 0, -30., -26., 0, -14., 24., 32., 8.}, { 0, 0, 6., 0, 0, 18., -14., 0, -26., -30., 0, -42., 8., 32., 24.}, { 0, 0, -6., 0, 0, -4., 30., 0, 4., 22., 0, 4., -24., -16., 0}, { 0, 0, -4., 0, 0, -8., 20., 0, 8., 36., 0, 8., -16., -32., 0}, { 0, 0, -8., 0, 0, -4., 8., 0, 36., 8., 0, 20., 0, -32., -16.}, { 0, 0, -4., 0, 0, -6., 4., 0, 22., 4., 0, 30., 0, -16., -24.} }; RT2TriangleFiniteElement::RT2TriangleFiniteElement() : VectorFiniteElement(2, Geometry::TRIANGLE, 15, 3, H_DIV) { const double p = 0.11270166537925831148; Nodes.IntPoint(0).x = p; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 0.5; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 1.-p; Nodes.IntPoint(2).y = 0.0; Nodes.IntPoint(3).x = 1.-p; Nodes.IntPoint(3).y = p; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = 0.5; Nodes.IntPoint(5).x = p; Nodes.IntPoint(5).y = 1.-p; Nodes.IntPoint(6).x = 0.0; Nodes.IntPoint(6).y = 1.-p; Nodes.IntPoint(7).x = 0.0; Nodes.IntPoint(7).y = 0.5; Nodes.IntPoint(8).x = 0.0; Nodes.IntPoint(8).y = p; Nodes.IntPoint(9).x = 0.25; Nodes.IntPoint(9).y = 0.25; Nodes.IntPoint(10).x = 0.25; Nodes.IntPoint(10).y = 0.25; Nodes.IntPoint(11).x = 0.5; Nodes.IntPoint(11).y = 0.25; Nodes.IntPoint(12).x = 0.5; Nodes.IntPoint(12).y = 0.25; Nodes.IntPoint(13).x = 0.25; Nodes.IntPoint(13).y = 0.5; Nodes.IntPoint(14).x = 0.25; Nodes.IntPoint(14).y = 0.5; } void RT2TriangleFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x = ip.x, y = ip.y; double Bx[15] = {1., 0., x, 0., y, 0., x*x, 0., x*y, 0., y*y, 0., x*x*x, x*x*y, x*y*y }; double By[15] = {0., 1., 0., x, 0., y, 0., x*x, 0., x*y, 0., y*y, x*x*y, x*y*y, y*y*y }; for (int i = 0; i < 15; i++) { double cx = 0.0, cy = 0.0; for (int j = 0; j < 15; j++) { cx += M[i][j] * Bx[j]; cy += M[i][j] * By[j]; } shape(i,0) = cx; shape(i,1) = cy; } } void RT2TriangleFiniteElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { double x = ip.x, y = ip.y; double DivB[15] = {0., 0., 1., 0., 0., 1., 2.*x, 0., y, x, 0., 2.*y, 4.*x*x, 4.*x*y, 4.*y*y }; for (int i = 0; i < 15; i++) { double div = 0.0; for (int j = 0; j < 15; j++) { div += M[i][j] * DivB[j]; } divshape(i) = div; } } const double RT2QuadFiniteElement::pt[4] = {0.,1./3.,2./3.,1.}; const double RT2QuadFiniteElement::dpt[3] = {0.25,0.5,0.75}; RT2QuadFiniteElement::RT2QuadFiniteElement() : VectorFiniteElement(2, Geometry::SQUARE, 24, 3, H_DIV, FunctionSpace::Qk) { // y = 0 (pt[0]) Nodes.IntPoint(0).x = dpt[0]; Nodes.IntPoint(0).y = pt[0]; Nodes.IntPoint(1).x = dpt[1]; Nodes.IntPoint(1).y = pt[0]; Nodes.IntPoint(2).x = dpt[2]; Nodes.IntPoint(2).y = pt[0]; // x = 1 (pt[3]) Nodes.IntPoint(3).x = pt[3]; Nodes.IntPoint(3).y = dpt[0]; Nodes.IntPoint(4).x = pt[3]; Nodes.IntPoint(4).y = dpt[1]; Nodes.IntPoint(5).x = pt[3]; Nodes.IntPoint(5).y = dpt[2]; // y = 1 (pt[3]) Nodes.IntPoint(6).x = dpt[2]; Nodes.IntPoint(6).y = pt[3]; Nodes.IntPoint(7).x = dpt[1]; Nodes.IntPoint(7).y = pt[3]; Nodes.IntPoint(8).x = dpt[0]; Nodes.IntPoint(8).y = pt[3]; // x = 0 (pt[0]) Nodes.IntPoint(9).x = pt[0]; Nodes.IntPoint(9).y = dpt[2]; Nodes.IntPoint(10).x = pt[0]; Nodes.IntPoint(10).y = dpt[1]; Nodes.IntPoint(11).x = pt[0]; Nodes.IntPoint(11).y = dpt[0]; // x = pt[1] (interior) Nodes.IntPoint(12).x = pt[1]; Nodes.IntPoint(12).y = dpt[0]; Nodes.IntPoint(13).x = pt[1]; Nodes.IntPoint(13).y = dpt[1]; Nodes.IntPoint(14).x = pt[1]; Nodes.IntPoint(14).y = dpt[2]; // x = pt[2] (interior) Nodes.IntPoint(15).x = pt[2]; Nodes.IntPoint(15).y = dpt[0]; Nodes.IntPoint(16).x = pt[2]; Nodes.IntPoint(16).y = dpt[1]; Nodes.IntPoint(17).x = pt[2]; Nodes.IntPoint(17).y = dpt[2]; // y = pt[1] (interior) Nodes.IntPoint(18).x = dpt[0]; Nodes.IntPoint(18).y = pt[1]; Nodes.IntPoint(19).x = dpt[1]; Nodes.IntPoint(19).y = pt[1]; Nodes.IntPoint(20).x = dpt[2]; Nodes.IntPoint(20).y = pt[1]; // y = pt[2] (interior) Nodes.IntPoint(21).x = dpt[0]; Nodes.IntPoint(21).y = pt[2]; Nodes.IntPoint(22).x = dpt[1]; Nodes.IntPoint(22).y = pt[2]; Nodes.IntPoint(23).x = dpt[2]; Nodes.IntPoint(23).y = pt[2]; } void RT2QuadFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x = ip.x, y = ip.y; double ax0 = pt[0] - x; double ax1 = pt[1] - x; double ax2 = pt[2] - x; double ax3 = pt[3] - x; double by0 = dpt[0] - y; double by1 = dpt[1] - y; double by2 = dpt[2] - y; double ay0 = pt[0] - y; double ay1 = pt[1] - y; double ay2 = pt[2] - y; double ay3 = pt[3] - y; double bx0 = dpt[0] - x; double bx1 = dpt[1] - x; double bx2 = dpt[2] - x; double A01 = pt[0] - pt[1]; double A02 = pt[0] - pt[2]; double A12 = pt[1] - pt[2]; double A03 = pt[0] - pt[3]; double A13 = pt[1] - pt[3]; double A23 = pt[2] - pt[3]; double B01 = dpt[0] - dpt[1]; double B02 = dpt[0] - dpt[2]; double B12 = dpt[1] - dpt[2]; double tx0 = (bx1*bx2)/(B01*B02); double tx1 = -(bx0*bx2)/(B01*B12); double tx2 = (bx0*bx1)/(B02*B12); double ty0 = (by1*by2)/(B01*B02); double ty1 = -(by0*by2)/(B01*B12); double ty2 = (by0*by1)/(B02*B12); // y = 0 (p[0]) shape(0, 0) = 0; shape(0, 1) = (ay1*ay2*ay3)/(A01*A02*A03)*tx0; shape(1, 0) = 0; shape(1, 1) = (ay1*ay2*ay3)/(A01*A02*A03)*tx1; shape(2, 0) = 0; shape(2, 1) = (ay1*ay2*ay3)/(A01*A02*A03)*tx2; // x = 1 (p[3]) shape(3, 0) = (ax0*ax1*ax2)/(A03*A13*A23)*ty0; shape(3, 1) = 0; shape(4, 0) = (ax0*ax1*ax2)/(A03*A13*A23)*ty1; shape(4, 1) = 0; shape(5, 0) = (ax0*ax1*ax2)/(A03*A13*A23)*ty2; shape(5, 1) = 0; // y = 1 (p[3]) shape(6, 0) = 0; shape(6, 1) = (ay0*ay1*ay2)/(A03*A13*A23)*tx2; shape(7, 0) = 0; shape(7, 1) = (ay0*ay1*ay2)/(A03*A13*A23)*tx1; shape(8, 0) = 0; shape(8, 1) = (ay0*ay1*ay2)/(A03*A13*A23)*tx0; // x = 0 (p[0]) shape(9, 0) = (ax1*ax2*ax3)/(A01*A02*A03)*ty2; shape(9, 1) = 0; shape(10, 0) = (ax1*ax2*ax3)/(A01*A02*A03)*ty1; shape(10, 1) = 0; shape(11, 0) = (ax1*ax2*ax3)/(A01*A02*A03)*ty0; shape(11, 1) = 0; // x = p[1] (interior) shape(12, 0) = (ax0*ax2*ax3)/(A01*A12*A13)*ty0; shape(12, 1) = 0; shape(13, 0) = (ax0*ax2*ax3)/(A01*A12*A13)*ty1; shape(13, 1) = 0; shape(14, 0) = (ax0*ax2*ax3)/(A01*A12*A13)*ty2; shape(14, 1) = 0; // x = p[2] (interior) shape(15, 0) = -(ax0*ax1*ax3)/(A02*A12*A23)*ty0; shape(15, 1) = 0; shape(16, 0) = -(ax0*ax1*ax3)/(A02*A12*A23)*ty1; shape(16, 1) = 0; shape(17, 0) = -(ax0*ax1*ax3)/(A02*A12*A23)*ty2; shape(17, 1) = 0; // y = p[1] (interior) shape(18, 0) = 0; shape(18, 1) = (ay0*ay2*ay3)/(A01*A12*A13)*tx0; shape(19, 0) = 0; shape(19, 1) = (ay0*ay2*ay3)/(A01*A12*A13)*tx1; shape(20, 0) = 0; shape(20, 1) = (ay0*ay2*ay3)/(A01*A12*A13)*tx2; // y = p[2] (interior) shape(21, 0) = 0; shape(21, 1) = -(ay0*ay1*ay3)/(A02*A12*A23)*tx0; shape(22, 0) = 0; shape(22, 1) = -(ay0*ay1*ay3)/(A02*A12*A23)*tx1; shape(23, 0) = 0; shape(23, 1) = -(ay0*ay1*ay3)/(A02*A12*A23)*tx2; } void RT2QuadFiniteElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { double x = ip.x, y = ip.y; double a01 = pt[0]*pt[1]; double a02 = pt[0]*pt[2]; double a12 = pt[1]*pt[2]; double a03 = pt[0]*pt[3]; double a13 = pt[1]*pt[3]; double a23 = pt[2]*pt[3]; double bx0 = dpt[0] - x; double bx1 = dpt[1] - x; double bx2 = dpt[2] - x; double by0 = dpt[0] - y; double by1 = dpt[1] - y; double by2 = dpt[2] - y; double A01 = pt[0] - pt[1]; double A02 = pt[0] - pt[2]; double A12 = pt[1] - pt[2]; double A03 = pt[0] - pt[3]; double A13 = pt[1] - pt[3]; double A23 = pt[2] - pt[3]; double A012 = pt[0] + pt[1] + pt[2]; double A013 = pt[0] + pt[1] + pt[3]; double A023 = pt[0] + pt[2] + pt[3]; double A123 = pt[1] + pt[2] + pt[3]; double B01 = dpt[0] - dpt[1]; double B02 = dpt[0] - dpt[2]; double B12 = dpt[1] - dpt[2]; double tx0 = (bx1*bx2)/(B01*B02); double tx1 = -(bx0*bx2)/(B01*B12); double tx2 = (bx0*bx1)/(B02*B12); double ty0 = (by1*by2)/(B01*B02); double ty1 = -(by0*by2)/(B01*B12); double ty2 = (by0*by1)/(B02*B12); // y = 0 (p[0]) divshape(0) = -(a12 + a13 + a23 - 2.*A123*y + 3.*y*y)/(A01*A02*A03)*tx0; divshape(1) = -(a12 + a13 + a23 - 2.*A123*y + 3.*y*y)/(A01*A02*A03)*tx1; divshape(2) = -(a12 + a13 + a23 - 2.*A123*y + 3.*y*y)/(A01*A02*A03)*tx2; // x = 1 (p[3]) divshape(3) = -(a01 + a02 + a12 - 2.*A012*x + 3.*x*x)/(A03*A13*A23)*ty0; divshape(4) = -(a01 + a02 + a12 - 2.*A012*x + 3.*x*x)/(A03*A13*A23)*ty1; divshape(5) = -(a01 + a02 + a12 - 2.*A012*x + 3.*x*x)/(A03*A13*A23)*ty2; // y = 1 (p[3]) divshape(6) = -(a01 + a02 + a12 - 2.*A012*y + 3.*y*y)/(A03*A13*A23)*tx2; divshape(7) = -(a01 + a02 + a12 - 2.*A012*y + 3.*y*y)/(A03*A13*A23)*tx1; divshape(8) = -(a01 + a02 + a12 - 2.*A012*y + 3.*y*y)/(A03*A13*A23)*tx0; // x = 0 (p[0]) divshape(9) = -(a12 + a13 + a23 - 2.*A123*x + 3.*x*x)/(A01*A02*A03)*ty2; divshape(10) = -(a12 + a13 + a23 - 2.*A123*x + 3.*x*x)/(A01*A02*A03)*ty1; divshape(11) = -(a12 + a13 + a23 - 2.*A123*x + 3.*x*x)/(A01*A02*A03)*ty0; // x = p[1] (interior) divshape(12) = -(a02 + a03 + a23 - 2.*A023*x + 3.*x*x)/(A01*A12*A13)*ty0; divshape(13) = -(a02 + a03 + a23 - 2.*A023*x + 3.*x*x)/(A01*A12*A13)*ty1; divshape(14) = -(a02 + a03 + a23 - 2.*A023*x + 3.*x*x)/(A01*A12*A13)*ty2; // x = p[2] (interior) divshape(15) = (a01 + a03 + a13 - 2.*A013*x + 3.*x*x)/(A02*A12*A23)*ty0; divshape(16) = (a01 + a03 + a13 - 2.*A013*x + 3.*x*x)/(A02*A12*A23)*ty1; divshape(17) = (a01 + a03 + a13 - 2.*A013*x + 3.*x*x)/(A02*A12*A23)*ty2; // y = p[1] (interior) divshape(18) = -(a02 + a03 + a23 - 2.*A023*y + 3.*y*y)/(A01*A12*A13)*tx0; divshape(19) = -(a02 + a03 + a23 - 2.*A023*y + 3.*y*y)/(A01*A12*A13)*tx1; divshape(20) = -(a02 + a03 + a23 - 2.*A023*y + 3.*y*y)/(A01*A12*A13)*tx2; // y = p[2] (interior) divshape(21) = (a01 + a03 + a13 - 2.*A013*y + 3.*y*y)/(A02*A12*A23)*tx0; divshape(22) = (a01 + a03 + a13 - 2.*A013*y + 3.*y*y)/(A02*A12*A23)*tx1; divshape(23) = (a01 + a03 + a13 - 2.*A013*y + 3.*y*y)/(A02*A12*A23)*tx2; } const double RT2QuadFiniteElement::nk[24][2] = { // y = 0 {0,-1}, {0,-1}, {0,-1}, // x = 1 {1, 0}, {1, 0}, {1, 0}, // y = 1 {0, 1}, {0, 1}, {0, 1}, // x = 0 {-1,0}, {-1,0}, {-1,0}, // x = p[1] (interior) {1, 0}, {1, 0}, {1, 0}, // x = p[2] (interior) {1, 0}, {1, 0}, {1, 0}, // y = p[1] (interior) {0, 1}, {0, 1}, {0, 1}, // y = p[1] (interior) {0, 1}, {0, 1}, {0, 1} }; void RT2QuadFiniteElement::GetLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I) const { int k, j; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG for (k = 0; k < 24; k++) { CalcVShape (Nodes.IntPoint(k), vshape); for (j = 0; j < 24; j++) { double d = vshape(j,0)*nk[k][0]+vshape(j,1)*nk[k][1]; if (j == k) { d -= 1.0; } if (fabs(d) > 1.0e-12) { mfem::err << "RT2QuadFiniteElement::GetLocalInterpolation (...)\n" " k = " << k << ", j = " << j << ", d = " << d << endl; mfem_error(); } } } #endif IntegrationPoint ip; ip.x = ip.y = 0.0; Trans.SetIntPoint (&ip); // Trans must be linear (more to have embedding?) // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); double vk[2]; Vector xk (vk, 2); for (k = 0; k < 24; k++) { Trans.Transform (Nodes.IntPoint (k), xk); ip.x = vk[0]; ip.y = vk[1]; CalcVShape (ip, vshape); // vk = |J| J^{-t} nk vk[0] = Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]; vk[1] = Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]; for (j = 0; j < 24; j++) if (fabs (I(k,j) = vshape(j,0)*vk[0]+vshape(j,1)*vk[1]) < 1.0e-12) { I(k,j) = 0.0; } } } void RT2QuadFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[2]; Vector xk (vk, 2); #ifdef MFEM_THREAD_SAFE DenseMatrix Jinv(dim); #endif for (int k = 0; k < 24; k++) { Trans.SetIntPoint (&Nodes.IntPoint (k)); // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); vc.Eval (xk, Trans, Nodes.IntPoint (k)); // xk^t |J| J^{-t} nk dofs(k) = (vk[0] * ( Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1] ) + vk[1] * ( Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1] )); } } P1SegmentFiniteElement::P1SegmentFiniteElement() : NodalFiniteElement(1, Geometry::SEGMENT, 2, 1) { Nodes.IntPoint(0).x = 0.33333333333333333333; Nodes.IntPoint(1).x = 0.66666666666666666667; } void P1SegmentFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = ip.x; shape(0) = 2. - 3. * x; shape(1) = 3. * x - 1.; } void P1SegmentFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = -3.; dshape(1,0) = 3.; } P2SegmentFiniteElement::P2SegmentFiniteElement() : NodalFiniteElement(1, Geometry::SEGMENT, 3, 2) { const double p = 0.11270166537925831148; Nodes.IntPoint(0).x = p; Nodes.IntPoint(1).x = 0.5; Nodes.IntPoint(2).x = 1.-p; } void P2SegmentFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const double p = 0.11270166537925831148; const double w = 1./((1-2*p)*(1-2*p)); double x = ip.x; shape(0) = (2*x-1)*(x-1+p)*w; shape(1) = 4*(x-1+p)*(p-x)*w; shape(2) = (2*x-1)*(x-p)*w; } void P2SegmentFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const double p = 0.11270166537925831148; const double w = 1./((1-2*p)*(1-2*p)); double x = ip.x; dshape(0,0) = (-3+4*x+2*p)*w; dshape(1,0) = (4-8*x)*w; dshape(2,0) = (-1+4*x-2*p)*w; } Lagrange1DFiniteElement::Lagrange1DFiniteElement(int degree) : NodalFiniteElement(1, Geometry::SEGMENT, degree+1, degree) { int i, m = degree; Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(1).x = 1.0; for (i = 1; i < m; i++) { Nodes.IntPoint(i+1).x = double(i) / m; } rwk.SetSize(degree+1); #ifndef MFEM_THREAD_SAFE rxxk.SetSize(degree+1); #endif rwk(0) = 1.0; for (i = 1; i <= m; i++) { rwk(i) = rwk(i-1) * ( (double)(m) / (double)(i) ); } for (i = 0; i < m/2+1; i++) { rwk(m-i) = ( rwk(i) *= rwk(m-i) ); } for (i = m-1; i >= 0; i -= 2) { rwk(i) = -rwk(i); } } void Lagrange1DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double w, wk, x = ip.x; int i, k, m = GetOrder(); #ifdef MFEM_THREAD_SAFE Vector rxxk(m+1); #endif k = (int) floor ( m * x + 0.5 ); k = k > m ? m : k < 0 ? 0 : k; // clamp k to [0,m] wk = 1.0; for (i = 0; i <= m; i++) if (i != k) { wk *= ( rxxk(i) = x - (double)(i) / m ); } w = wk * ( rxxk(k) = x - (double)(k) / m ); if (k != 0) { shape(0) = w * rwk(0) / rxxk(0); } else { shape(0) = wk * rwk(0); } if (k != m) { shape(1) = w * rwk(m) / rxxk(m); } else { shape(1) = wk * rwk(k); } for (i = 1; i < m; i++) if (i != k) { shape(i+1) = w * rwk(i) / rxxk(i); } else { shape(k+1) = wk * rwk(k); } } void Lagrange1DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double s, srx, w, wk, x = ip.x; int i, k, m = GetOrder(); #ifdef MFEM_THREAD_SAFE Vector rxxk(m+1); #endif k = (int) floor ( m * x + 0.5 ); k = k > m ? m : k < 0 ? 0 : k; // clamp k to [0,m] wk = 1.0; for (i = 0; i <= m; i++) if (i != k) { wk *= ( rxxk(i) = x - (double)(i) / m ); } w = wk * ( rxxk(k) = x - (double)(k) / m ); for (i = 0; i <= m; i++) { rxxk(i) = 1.0 / rxxk(i); } srx = 0.0; for (i = 0; i <= m; i++) if (i != k) { srx += rxxk(i); } s = w * srx + wk; if (k != 0) { dshape(0,0) = (s - w * rxxk(0)) * rwk(0) * rxxk(0); } else { dshape(0,0) = wk * srx * rwk(0); } if (k != m) { dshape(1,0) = (s - w * rxxk(m)) * rwk(m) * rxxk(m); } else { dshape(1,0) = wk * srx * rwk(k); } for (i = 1; i < m; i++) if (i != k) { dshape(i+1,0) = (s - w * rxxk(i)) * rwk(i) * rxxk(i); } else { dshape(k+1,0) = wk * srx * rwk(k); } } P1TetNonConfFiniteElement::P1TetNonConfFiniteElement() : NodalFiniteElement(3, Geometry::TETRAHEDRON, 4, 1) { Nodes.IntPoint(0).x = 0.33333333333333333333; Nodes.IntPoint(0).y = 0.33333333333333333333; Nodes.IntPoint(0).z = 0.33333333333333333333; Nodes.IntPoint(1).x = 0.0; Nodes.IntPoint(1).y = 0.33333333333333333333; Nodes.IntPoint(1).z = 0.33333333333333333333; Nodes.IntPoint(2).x = 0.33333333333333333333; Nodes.IntPoint(2).y = 0.0; Nodes.IntPoint(2).z = 0.33333333333333333333; Nodes.IntPoint(3).x = 0.33333333333333333333; Nodes.IntPoint(3).y = 0.33333333333333333333; Nodes.IntPoint(3).z = 0.0; } void P1TetNonConfFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double L0, L1, L2, L3; L1 = ip.x; L2 = ip.y; L3 = ip.z; L0 = 1.0 - L1 - L2 - L3; shape(0) = 1.0 - 3.0 * L0; shape(1) = 1.0 - 3.0 * L1; shape(2) = 1.0 - 3.0 * L2; shape(3) = 1.0 - 3.0 * L3; } void P1TetNonConfFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = 3.0; dshape(0,1) = 3.0; dshape(0,2) = 3.0; dshape(1,0) = -3.0; dshape(1,1) = 0.0; dshape(1,2) = 0.0; dshape(2,0) = 0.0; dshape(2,1) = -3.0; dshape(2,2) = 0.0; dshape(3,0) = 0.0; dshape(3,1) = 0.0; dshape(3,2) = -3.0; } P0TetFiniteElement::P0TetFiniteElement() : NodalFiniteElement(3, Geometry::TETRAHEDRON, 1, 0) { Nodes.IntPoint(0).x = 0.25; Nodes.IntPoint(0).y = 0.25; Nodes.IntPoint(0).z = 0.25; } void P0TetFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1.0; } void P0TetFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = 0.0; dshape(0,1) = 0.0; dshape(0,2) = 0.0; } P0HexFiniteElement::P0HexFiniteElement() : NodalFiniteElement(3, Geometry::CUBE, 1, 0, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.5; Nodes.IntPoint(0).y = 0.5; Nodes.IntPoint(0).z = 0.5; } void P0HexFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { shape(0) = 1.0; } void P0HexFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { dshape(0,0) = 0.0; dshape(0,1) = 0.0; dshape(0,2) = 0.0; } LagrangeHexFiniteElement::LagrangeHexFiniteElement (int degree) : NodalFiniteElement(3, Geometry::CUBE, (degree+1)*(degree+1)*(degree+1), degree, FunctionSpace::Qk) { if (degree == 2) { I = new int[dof]; J = new int[dof]; K = new int[dof]; // nodes I[ 0] = 0; J[ 0] = 0; K[ 0] = 0; I[ 1] = 1; J[ 1] = 0; K[ 1] = 0; I[ 2] = 1; J[ 2] = 1; K[ 2] = 0; I[ 3] = 0; J[ 3] = 1; K[ 3] = 0; I[ 4] = 0; J[ 4] = 0; K[ 4] = 1; I[ 5] = 1; J[ 5] = 0; K[ 5] = 1; I[ 6] = 1; J[ 6] = 1; K[ 6] = 1; I[ 7] = 0; J[ 7] = 1; K[ 7] = 1; // edges I[ 8] = 2; J[ 8] = 0; K[ 8] = 0; I[ 9] = 1; J[ 9] = 2; K[ 9] = 0; I[10] = 2; J[10] = 1; K[10] = 0; I[11] = 0; J[11] = 2; K[11] = 0; I[12] = 2; J[12] = 0; K[12] = 1; I[13] = 1; J[13] = 2; K[13] = 1; I[14] = 2; J[14] = 1; K[14] = 1; I[15] = 0; J[15] = 2; K[15] = 1; I[16] = 0; J[16] = 0; K[16] = 2; I[17] = 1; J[17] = 0; K[17] = 2; I[18] = 1; J[18] = 1; K[18] = 2; I[19] = 0; J[19] = 1; K[19] = 2; // faces I[20] = 2; J[20] = 2; K[20] = 0; I[21] = 2; J[21] = 0; K[21] = 2; I[22] = 1; J[22] = 2; K[22] = 2; I[23] = 2; J[23] = 1; K[23] = 2; I[24] = 0; J[24] = 2; K[24] = 2; I[25] = 2; J[25] = 2; K[25] = 1; // element I[26] = 2; J[26] = 2; K[26] = 2; } else if (degree == 3) { I = new int[dof]; J = new int[dof]; K = new int[dof]; // nodes I[ 0] = 0; J[ 0] = 0; K[ 0] = 0; I[ 1] = 1; J[ 1] = 0; K[ 1] = 0; I[ 2] = 1; J[ 2] = 1; K[ 2] = 0; I[ 3] = 0; J[ 3] = 1; K[ 3] = 0; I[ 4] = 0; J[ 4] = 0; K[ 4] = 1; I[ 5] = 1; J[ 5] = 0; K[ 5] = 1; I[ 6] = 1; J[ 6] = 1; K[ 6] = 1; I[ 7] = 0; J[ 7] = 1; K[ 7] = 1; // edges I[ 8] = 2; J[ 8] = 0; K[ 8] = 0; I[ 9] = 3; J[ 9] = 0; K[ 9] = 0; I[10] = 1; J[10] = 2; K[10] = 0; I[11] = 1; J[11] = 3; K[11] = 0; I[12] = 2; J[12] = 1; K[12] = 0; I[13] = 3; J[13] = 1; K[13] = 0; I[14] = 0; J[14] = 2; K[14] = 0; I[15] = 0; J[15] = 3; K[15] = 0; I[16] = 2; J[16] = 0; K[16] = 1; I[17] = 3; J[17] = 0; K[17] = 1; I[18] = 1; J[18] = 2; K[18] = 1; I[19] = 1; J[19] = 3; K[19] = 1; I[20] = 2; J[20] = 1; K[20] = 1; I[21] = 3; J[21] = 1; K[21] = 1; I[22] = 0; J[22] = 2; K[22] = 1; I[23] = 0; J[23] = 3; K[23] = 1; I[24] = 0; J[24] = 0; K[24] = 2; I[25] = 0; J[25] = 0; K[25] = 3; I[26] = 1; J[26] = 0; K[26] = 2; I[27] = 1; J[27] = 0; K[27] = 3; I[28] = 1; J[28] = 1; K[28] = 2; I[29] = 1; J[29] = 1; K[29] = 3; I[30] = 0; J[30] = 1; K[30] = 2; I[31] = 0; J[31] = 1; K[31] = 3; // faces I[32] = 2; J[32] = 3; K[32] = 0; I[33] = 3; J[33] = 3; K[33] = 0; I[34] = 2; J[34] = 2; K[34] = 0; I[35] = 3; J[35] = 2; K[35] = 0; I[36] = 2; J[36] = 0; K[36] = 2; I[37] = 3; J[37] = 0; K[37] = 2; I[38] = 2; J[38] = 0; K[38] = 3; I[39] = 3; J[39] = 0; K[39] = 3; I[40] = 1; J[40] = 2; K[40] = 2; I[41] = 1; J[41] = 3; K[41] = 2; I[42] = 1; J[42] = 2; K[42] = 3; I[43] = 1; J[43] = 3; K[43] = 3; I[44] = 3; J[44] = 1; K[44] = 2; I[45] = 2; J[45] = 1; K[45] = 2; I[46] = 3; J[46] = 1; K[46] = 3; I[47] = 2; J[47] = 1; K[47] = 3; I[48] = 0; J[48] = 3; K[48] = 2; I[49] = 0; J[49] = 2; K[49] = 2; I[50] = 0; J[50] = 3; K[50] = 3; I[51] = 0; J[51] = 2; K[51] = 3; I[52] = 2; J[52] = 2; K[52] = 1; I[53] = 3; J[53] = 2; K[53] = 1; I[54] = 2; J[54] = 3; K[54] = 1; I[55] = 3; J[55] = 3; K[55] = 1; // element I[56] = 2; J[56] = 2; K[56] = 2; I[57] = 3; J[57] = 2; K[57] = 2; I[58] = 3; J[58] = 3; K[58] = 2; I[59] = 2; J[59] = 3; K[59] = 2; I[60] = 2; J[60] = 2; K[60] = 3; I[61] = 3; J[61] = 2; K[61] = 3; I[62] = 3; J[62] = 3; K[62] = 3; I[63] = 2; J[63] = 3; K[63] = 3; } else { mfem_error ("LagrangeHexFiniteElement::LagrangeHexFiniteElement"); } fe1d = new Lagrange1DFiniteElement(degree); dof1d = fe1d -> GetDof(); #ifndef MFEM_THREAD_SAFE shape1dx.SetSize(dof1d); shape1dy.SetSize(dof1d); shape1dz.SetSize(dof1d); dshape1dx.SetSize(dof1d,1); dshape1dy.SetSize(dof1d,1); dshape1dz.SetSize(dof1d,1); #endif for (int n = 0; n < dof; n++) { Nodes.IntPoint(n).x = fe1d -> GetNodes().IntPoint(I[n]).x; Nodes.IntPoint(n).y = fe1d -> GetNodes().IntPoint(J[n]).x; Nodes.IntPoint(n).z = fe1d -> GetNodes().IntPoint(K[n]).x; } } void LagrangeHexFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { IntegrationPoint ipy, ipz; ipy.x = ip.y; ipz.x = ip.z; #ifdef MFEM_THREAD_SAFE Vector shape1dx(dof1d), shape1dy(dof1d), shape1dz(dof1d); #endif fe1d -> CalcShape(ip, shape1dx); fe1d -> CalcShape(ipy, shape1dy); fe1d -> CalcShape(ipz, shape1dz); for (int n = 0; n < dof; n++) { shape(n) = shape1dx(I[n]) * shape1dy(J[n]) * shape1dz(K[n]); } } void LagrangeHexFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { IntegrationPoint ipy, ipz; ipy.x = ip.y; ipz.x = ip.z; #ifdef MFEM_THREAD_SAFE Vector shape1dx(dof1d), shape1dy(dof1d), shape1dz(dof1d); DenseMatrix dshape1dx(dof1d,1), dshape1dy(dof1d,1), dshape1dz(dof1d,1); #endif fe1d -> CalcShape(ip, shape1dx); fe1d -> CalcShape(ipy, shape1dy); fe1d -> CalcShape(ipz, shape1dz); fe1d -> CalcDShape(ip, dshape1dx); fe1d -> CalcDShape(ipy, dshape1dy); fe1d -> CalcDShape(ipz, dshape1dz); for (int n = 0; n < dof; n++) { dshape(n,0) = dshape1dx(I[n],0) * shape1dy(J[n]) * shape1dz(K[n]); dshape(n,1) = shape1dx(I[n]) * dshape1dy(J[n],0) * shape1dz(K[n]); dshape(n,2) = shape1dx(I[n]) * shape1dy(J[n]) * dshape1dz(K[n],0); } } LagrangeHexFiniteElement::~LagrangeHexFiniteElement () { delete fe1d; delete [] I; delete [] J; delete [] K; } RefinedLinear1DFiniteElement::RefinedLinear1DFiniteElement() : NodalFiniteElement(1, Geometry::SEGMENT, 3, 4) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(2).x = 0.5; } void RefinedLinear1DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = ip.x; if (x <= 0.5) { shape(0) = 1.0 - 2.0 * x; shape(1) = 0.0; shape(2) = 2.0 * x; } else { shape(0) = 0.0; shape(1) = 2.0 * x - 1.0; shape(2) = 2.0 - 2.0 * x; } } void RefinedLinear1DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double x = ip.x; if (x <= 0.5) { dshape(0,0) = - 2.0; dshape(1,0) = 0.0; dshape(2,0) = 2.0; } else { dshape(0,0) = 0.0; dshape(1,0) = 2.0; dshape(2,0) = - 2.0; } } RefinedLinear2DFiniteElement::RefinedLinear2DFiniteElement() : NodalFiniteElement(2, Geometry::TRIANGLE, 6, 5) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(3).x = 0.5; Nodes.IntPoint(3).y = 0.0; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = 0.5; Nodes.IntPoint(5).x = 0.0; Nodes.IntPoint(5).y = 0.5; } void RefinedLinear2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { int i; double L0, L1, L2; L0 = 2.0 * ( 1. - ip.x - ip.y ); L1 = 2.0 * ( ip.x ); L2 = 2.0 * ( ip.y ); // The reference triangle is split in 4 triangles as follows: // // T0 - 0,3,5 // T1 - 1,3,4 // T2 - 2,4,5 // T3 - 3,4,5 for (i = 0; i < 6; i++) { shape(i) = 0.0; } if (L0 >= 1.0) // T0 { shape(0) = L0 - 1.0; shape(3) = L1; shape(5) = L2; } else if (L1 >= 1.0) // T1 { shape(3) = L0; shape(1) = L1 - 1.0; shape(4) = L2; } else if (L2 >= 1.0) // T2 { shape(5) = L0; shape(4) = L1; shape(2) = L2 - 1.0; } else // T3 { shape(3) = 1.0 - L2; shape(4) = 1.0 - L0; shape(5) = 1.0 - L1; } } void RefinedLinear2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { int i,j; double L0, L1, L2; L0 = 2.0 * ( 1. - ip.x - ip.y ); L1 = 2.0 * ( ip.x ); L2 = 2.0 * ( ip.y ); double DL0[2], DL1[2], DL2[2]; DL0[0] = -2.0; DL0[1] = -2.0; DL1[0] = 2.0; DL1[1] = 0.0; DL2[0] = 0.0; DL2[1] = 2.0; for (i = 0; i < 6; i++) for (j = 0; j < 2; j++) { dshape(i,j) = 0.0; } if (L0 >= 1.0) // T0 { for (j = 0; j < 2; j++) { dshape(0,j) = DL0[j]; dshape(3,j) = DL1[j]; dshape(5,j) = DL2[j]; } } else if (L1 >= 1.0) // T1 { for (j = 0; j < 2; j++) { dshape(3,j) = DL0[j]; dshape(1,j) = DL1[j]; dshape(4,j) = DL2[j]; } } else if (L2 >= 1.0) // T2 { for (j = 0; j < 2; j++) { dshape(5,j) = DL0[j]; dshape(4,j) = DL1[j]; dshape(2,j) = DL2[j]; } } else // T3 { for (j = 0; j < 2; j++) { dshape(3,j) = - DL2[j]; dshape(4,j) = - DL0[j]; dshape(5,j) = - DL1[j]; } } } RefinedLinear3DFiniteElement::RefinedLinear3DFiniteElement() : NodalFiniteElement(3, Geometry::TETRAHEDRON, 10, 4) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(0).z = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(1).z = 0.0; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(2).z = 0.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 0.0; Nodes.IntPoint(3).z = 1.0; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = 0.0; Nodes.IntPoint(4).z = 0.0; Nodes.IntPoint(5).x = 0.0; Nodes.IntPoint(5).y = 0.5; Nodes.IntPoint(5).z = 0.0; Nodes.IntPoint(6).x = 0.0; Nodes.IntPoint(6).y = 0.0; Nodes.IntPoint(6).z = 0.5; Nodes.IntPoint(7).x = 0.5; Nodes.IntPoint(7).y = 0.5; Nodes.IntPoint(7).z = 0.0; Nodes.IntPoint(8).x = 0.5; Nodes.IntPoint(8).y = 0.0; Nodes.IntPoint(8).z = 0.5; Nodes.IntPoint(9).x = 0.0; Nodes.IntPoint(9).y = 0.5; Nodes.IntPoint(9).z = 0.5; } void RefinedLinear3DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { int i; double L0, L1, L2, L3, L4, L5; L0 = 2.0 * ( 1. - ip.x - ip.y - ip.z ); L1 = 2.0 * ( ip.x ); L2 = 2.0 * ( ip.y ); L3 = 2.0 * ( ip.z ); L4 = 2.0 * ( ip.x + ip.y ); L5 = 2.0 * ( ip.y + ip.z ); // The reference tetrahedron is split in 8 tetrahedra as follows: // // T0 - 0,4,5,6 // T1 - 1,4,7,8 // T2 - 2,5,7,9 // T3 - 3,6,8,9 // T4 - 4,5,6,8 // T5 - 4,5,7,8 // T6 - 5,6,8,9 // T7 - 5,7,8,9 for (i = 0; i < 10; i++) { shape(i) = 0.0; } if (L0 >= 1.0) // T0 { shape(0) = L0 - 1.0; shape(4) = L1; shape(5) = L2; shape(6) = L3; } else if (L1 >= 1.0) // T1 { shape(4) = L0; shape(1) = L1 - 1.0; shape(7) = L2; shape(8) = L3; } else if (L2 >= 1.0) // T2 { shape(5) = L0; shape(7) = L1; shape(2) = L2 - 1.0; shape(9) = L3; } else if (L3 >= 1.0) // T3 { shape(6) = L0; shape(8) = L1; shape(9) = L2; shape(3) = L3 - 1.0; } else if ((L4 <= 1.0) && (L5 <= 1.0)) // T4 { shape(4) = 1.0 - L5; shape(5) = L2; shape(6) = 1.0 - L4; shape(8) = 1.0 - L0; } else if ((L4 >= 1.0) && (L5 <= 1.0)) // T5 { shape(4) = 1.0 - L5; shape(5) = 1.0 - L1; shape(7) = L4 - 1.0; shape(8) = L3; } else if ((L4 <= 1.0) && (L5 >= 1.0)) // T6 { shape(5) = 1.0 - L3; shape(6) = 1.0 - L4; shape(8) = L1; shape(9) = L5 - 1.0; } else if ((L4 >= 1.0) && (L5 >= 1.0)) // T7 { shape(5) = L0; shape(7) = L4 - 1.0; shape(8) = 1.0 - L2; shape(9) = L5 - 1.0; } } void RefinedLinear3DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { int i,j; double L0, L1, L2, L3, L4, L5; L0 = 2.0 * ( 1. - ip.x - ip.y - ip.z ); L1 = 2.0 * ( ip.x ); L2 = 2.0 * ( ip.y ); L3 = 2.0 * ( ip.z ); L4 = 2.0 * ( ip.x + ip.y ); L5 = 2.0 * ( ip.y + ip.z ); double DL0[3], DL1[3], DL2[3], DL3[3], DL4[3], DL5[3]; DL0[0] = -2.0; DL0[1] = -2.0; DL0[2] = -2.0; DL1[0] = 2.0; DL1[1] = 0.0; DL1[2] = 0.0; DL2[0] = 0.0; DL2[1] = 2.0; DL2[2] = 0.0; DL3[0] = 0.0; DL3[1] = 0.0; DL3[2] = 2.0; DL4[0] = 2.0; DL4[1] = 2.0; DL4[2] = 0.0; DL5[0] = 0.0; DL5[1] = 2.0; DL5[2] = 2.0; for (i = 0; i < 10; i++) for (j = 0; j < 3; j++) { dshape(i,j) = 0.0; } if (L0 >= 1.0) // T0 { for (j = 0; j < 3; j++) { dshape(0,j) = DL0[j]; dshape(4,j) = DL1[j]; dshape(5,j) = DL2[j]; dshape(6,j) = DL3[j]; } } else if (L1 >= 1.0) // T1 { for (j = 0; j < 3; j++) { dshape(4,j) = DL0[j]; dshape(1,j) = DL1[j]; dshape(7,j) = DL2[j]; dshape(8,j) = DL3[j]; } } else if (L2 >= 1.0) // T2 { for (j = 0; j < 3; j++) { dshape(5,j) = DL0[j]; dshape(7,j) = DL1[j]; dshape(2,j) = DL2[j]; dshape(9,j) = DL3[j]; } } else if (L3 >= 1.0) // T3 { for (j = 0; j < 3; j++) { dshape(6,j) = DL0[j]; dshape(8,j) = DL1[j]; dshape(9,j) = DL2[j]; dshape(3,j) = DL3[j]; } } else if ((L4 <= 1.0) && (L5 <= 1.0)) // T4 { for (j = 0; j < 3; j++) { dshape(4,j) = - DL5[j]; dshape(5,j) = DL2[j]; dshape(6,j) = - DL4[j]; dshape(8,j) = - DL0[j]; } } else if ((L4 >= 1.0) && (L5 <= 1.0)) // T5 { for (j = 0; j < 3; j++) { dshape(4,j) = - DL5[j]; dshape(5,j) = - DL1[j]; dshape(7,j) = DL4[j]; dshape(8,j) = DL3[j]; } } else if ((L4 <= 1.0) && (L5 >= 1.0)) // T6 { for (j = 0; j < 3; j++) { dshape(5,j) = - DL3[j]; dshape(6,j) = - DL4[j]; dshape(8,j) = DL1[j]; dshape(9,j) = DL5[j]; } } else if ((L4 >= 1.0) && (L5 >= 1.0)) // T7 { for (j = 0; j < 3; j++) { dshape(5,j) = DL0[j]; dshape(7,j) = DL4[j]; dshape(8,j) = - DL2[j]; dshape(9,j) = DL5[j]; } } } RefinedBiLinear2DFiniteElement::RefinedBiLinear2DFiniteElement() : NodalFiniteElement(2, Geometry::SQUARE, 9, 1, FunctionSpace::rQk) { Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(2).x = 1.0; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 1.0; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = 0.0; Nodes.IntPoint(5).x = 1.0; Nodes.IntPoint(5).y = 0.5; Nodes.IntPoint(6).x = 0.5; Nodes.IntPoint(6).y = 1.0; Nodes.IntPoint(7).x = 0.0; Nodes.IntPoint(7).y = 0.5; Nodes.IntPoint(8).x = 0.5; Nodes.IntPoint(8).y = 0.5; } void RefinedBiLinear2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { int i; double x = ip.x, y = ip.y; double Lx, Ly; Lx = 2.0 * ( 1. - x ); Ly = 2.0 * ( 1. - y ); // The reference square is split in 4 squares as follows: // // T0 - 0,4,7,8 // T1 - 1,4,5,8 // T2 - 2,5,6,8 // T3 - 3,6,7,8 for (i = 0; i < 9; i++) { shape(i) = 0.0; } if ((x <= 0.5) && (y <= 0.5)) // T0 { shape(0) = (Lx - 1.0) * (Ly - 1.0); shape(4) = (2.0 - Lx) * (Ly - 1.0); shape(8) = (2.0 - Lx) * (2.0 - Ly); shape(7) = (Lx - 1.0) * (2.0 - Ly); } else if ((x >= 0.5) && (y <= 0.5)) // T1 { shape(4) = Lx * (Ly - 1.0); shape(1) = (1.0 - Lx) * (Ly - 1.0); shape(5) = (1.0 - Lx) * (2.0 - Ly); shape(8) = Lx * (2.0 - Ly); } else if ((x >= 0.5) && (y >= 0.5)) // T2 { shape(8) = Lx * Ly ; shape(5) = (1.0 - Lx) * Ly ; shape(2) = (1.0 - Lx) * (1.0 - Ly); shape(6) = Lx * (1.0 - Ly); } else if ((x <= 0.5) && (y >= 0.5)) // T3 { shape(7) = (Lx - 1.0) * Ly ; shape(8) = (2.0 - Lx) * Ly ; shape(6) = (2.0 - Lx) * (1.0 - Ly); shape(3) = (Lx - 1.0) * (1.0 - Ly); } } void RefinedBiLinear2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { int i,j; double x = ip.x, y = ip.y; double Lx, Ly; Lx = 2.0 * ( 1. - x ); Ly = 2.0 * ( 1. - y ); for (i = 0; i < 9; i++) for (j = 0; j < 2; j++) { dshape(i,j) = 0.0; } if ((x <= 0.5) && (y <= 0.5)) // T0 { dshape(0,0) = 2.0 * (1.0 - Ly); dshape(0,1) = 2.0 * (1.0 - Lx); dshape(4,0) = 2.0 * (Ly - 1.0); dshape(4,1) = -2.0 * (2.0 - Lx); dshape(8,0) = 2.0 * (2.0 - Ly); dshape(8,1) = 2.0 * (2.0 - Lx); dshape(7,0) = -2.0 * (2.0 - Ly); dshape(7,0) = 2.0 * (Lx - 1.0); } else if ((x >= 0.5) && (y <= 0.5)) // T1 { dshape(4,0) = -2.0 * (Ly - 1.0); dshape(4,1) = -2.0 * Lx; dshape(1,0) = 2.0 * (Ly - 1.0); dshape(1,1) = -2.0 * (1.0 - Lx); dshape(5,0) = 2.0 * (2.0 - Ly); dshape(5,1) = 2.0 * (1.0 - Lx); dshape(8,0) = -2.0 * (2.0 - Ly); dshape(8,1) = 2.0 * Lx; } else if ((x >= 0.5) && (y >= 0.5)) // T2 { dshape(8,0) = -2.0 * Ly; dshape(8,1) = -2.0 * Lx; dshape(5,0) = 2.0 * Ly; dshape(5,1) = -2.0 * (1.0 - Lx); dshape(2,0) = 2.0 * (1.0 - Ly); dshape(2,1) = 2.0 * (1.0 - Lx); dshape(6,0) = -2.0 * (1.0 - Ly); dshape(6,1) = 2.0 * Lx; } else if ((x <= 0.5) && (y >= 0.5)) // T3 { dshape(7,0) = -2.0 * Ly; dshape(7,1) = -2.0 * (Lx - 1.0); dshape(8,0) = 2.0 * Ly ; dshape(8,1) = -2.0 * (2.0 - Lx); dshape(6,0) = 2.0 * (1.0 - Ly); dshape(6,1) = 2.0 * (2.0 - Lx); dshape(3,0) = -2.0 * (1.0 - Ly); dshape(3,1) = 2.0 * (Lx - 1.0); } } RefinedTriLinear3DFiniteElement::RefinedTriLinear3DFiniteElement() : NodalFiniteElement(3, Geometry::CUBE, 27, 2, FunctionSpace::rQk) { double I[27]; double J[27]; double K[27]; // nodes I[ 0] = 0.0; J[ 0] = 0.0; K[ 0] = 0.0; I[ 1] = 1.0; J[ 1] = 0.0; K[ 1] = 0.0; I[ 2] = 1.0; J[ 2] = 1.0; K[ 2] = 0.0; I[ 3] = 0.0; J[ 3] = 1.0; K[ 3] = 0.0; I[ 4] = 0.0; J[ 4] = 0.0; K[ 4] = 1.0; I[ 5] = 1.0; J[ 5] = 0.0; K[ 5] = 1.0; I[ 6] = 1.0; J[ 6] = 1.0; K[ 6] = 1.0; I[ 7] = 0.0; J[ 7] = 1.0; K[ 7] = 1.0; // edges I[ 8] = 0.5; J[ 8] = 0.0; K[ 8] = 0.0; I[ 9] = 1.0; J[ 9] = 0.5; K[ 9] = 0.0; I[10] = 0.5; J[10] = 1.0; K[10] = 0.0; I[11] = 0.0; J[11] = 0.5; K[11] = 0.0; I[12] = 0.5; J[12] = 0.0; K[12] = 1.0; I[13] = 1.0; J[13] = 0.5; K[13] = 1.0; I[14] = 0.5; J[14] = 1.0; K[14] = 1.0; I[15] = 0.0; J[15] = 0.5; K[15] = 1.0; I[16] = 0.0; J[16] = 0.0; K[16] = 0.5; I[17] = 1.0; J[17] = 0.0; K[17] = 0.5; I[18] = 1.0; J[18] = 1.0; K[18] = 0.5; I[19] = 0.0; J[19] = 1.0; K[19] = 0.5; // faces I[20] = 0.5; J[20] = 0.5; K[20] = 0.0; I[21] = 0.5; J[21] = 0.0; K[21] = 0.5; I[22] = 1.0; J[22] = 0.5; K[22] = 0.5; I[23] = 0.5; J[23] = 1.0; K[23] = 0.5; I[24] = 0.0; J[24] = 0.5; K[24] = 0.5; I[25] = 0.5; J[25] = 0.5; K[25] = 1.0; // element I[26] = 0.5; J[26] = 0.5; K[26] = 0.5; for (int n = 0; n < 27; n++) { Nodes.IntPoint(n).x = I[n]; Nodes.IntPoint(n).y = J[n]; Nodes.IntPoint(n).z = K[n]; } } void RefinedTriLinear3DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { int i, N[8]; double Lx, Ly, Lz; double x = ip.x, y = ip.y, z = ip.z; for (i = 0; i < 27; i++) { shape(i) = 0.0; } if ((x <= 0.5) && (y <= 0.5) && (z <= 0.5)) // T0 { Lx = 1.0 - 2.0 * x; Ly = 1.0 - 2.0 * y; Lz = 1.0 - 2.0 * z; N[0] = 0; N[1] = 8; N[2] = 20; N[3] = 11; N[4] = 16; N[5] = 21; N[6] = 26; N[7] = 24; } else if ((x >= 0.5) && (y <= 0.5) && (z <= 0.5)) // T1 { Lx = 2.0 - 2.0 * x; Ly = 1.0 - 2.0 * y; Lz = 1.0 - 2.0 * z; N[0] = 8; N[1] = 1; N[2] = 9; N[3] = 20; N[4] = 21; N[5] = 17; N[6] = 22; N[7] = 26; } else if ((x <= 0.5) && (y >= 0.5) && (z <= 0.5)) // T2 { Lx = 2.0 - 2.0 * x; Ly = 2.0 - 2.0 * y; Lz = 1.0 - 2.0 * z; N[0] = 20; N[1] = 9; N[2] = 2; N[3] = 10; N[4] = 26; N[5] = 22; N[6] = 18; N[7] = 23; } else if ((x >= 0.5) && (y >= 0.5) && (z <= 0.5)) // T3 { Lx = 1.0 - 2.0 * x; Ly = 2.0 - 2.0 * y; Lz = 1.0 - 2.0 * z; N[0] = 11; N[1] = 20; N[2] = 10; N[3] = 3; N[4] = 24; N[5] = 26; N[6] = 23; N[7] = 19; } else if ((x <= 0.5) && (y <= 0.5) && (z >= 0.5)) // T4 { Lx = 1.0 - 2.0 * x; Ly = 1.0 - 2.0 * y; Lz = 2.0 - 2.0 * z; N[0] = 16; N[1] = 21; N[2] = 26; N[3] = 24; N[4] = 4; N[5] = 12; N[6] = 25; N[7] = 15; } else if ((x >= 0.5) && (y <= 0.5) && (z >= 0.5)) // T5 { Lx = 2.0 - 2.0 * x; Ly = 1.0 - 2.0 * y; Lz = 2.0 - 2.0 * z; N[0] = 21; N[1] = 17; N[2] = 22; N[3] = 26; N[4] = 12; N[5] = 5; N[6] = 13; N[7] = 25; } else if ((x <= 0.5) && (y >= 0.5) && (z >= 0.5)) // T6 { Lx = 2.0 - 2.0 * x; Ly = 2.0 - 2.0 * y; Lz = 2.0 - 2.0 * z; N[0] = 26; N[1] = 22; N[2] = 18; N[3] = 23; N[4] = 25; N[5] = 13; N[6] = 6; N[7] = 14; } else // T7 { Lx = 1.0 - 2.0 * x; Ly = 2.0 - 2.0 * y; Lz = 2.0 - 2.0 * z; N[0] = 24; N[1] = 26; N[2] = 23; N[3] = 19; N[4] = 15; N[5] = 25; N[6] = 14; N[7] = 7; } shape(N[0]) = Lx * Ly * Lz; shape(N[1]) = (1 - Lx) * Ly * Lz; shape(N[2]) = (1 - Lx) * (1 - Ly) * Lz; shape(N[3]) = Lx * (1 - Ly) * Lz; shape(N[4]) = Lx * Ly * (1 - Lz); shape(N[5]) = (1 - Lx) * Ly * (1 - Lz); shape(N[6]) = (1 - Lx) * (1 - Ly) * (1 - Lz); shape(N[7]) = Lx * (1 - Ly) * (1 - Lz); } void RefinedTriLinear3DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { int i, j, N[8]; double Lx, Ly, Lz; double x = ip.x, y = ip.y, z = ip.z; for (i = 0; i < 27; i++) for (j = 0; j < 3; j++) { dshape(i,j) = 0.0; } if ((x <= 0.5) && (y <= 0.5) && (z <= 0.5)) // T0 { Lx = 1.0 - 2.0 * x; Ly = 1.0 - 2.0 * y; Lz = 1.0 - 2.0 * z; N[0] = 0; N[1] = 8; N[2] = 20; N[3] = 11; N[4] = 16; N[5] = 21; N[6] = 26; N[7] = 24; } else if ((x >= 0.5) && (y <= 0.5) && (z <= 0.5)) // T1 { Lx = 2.0 - 2.0 * x; Ly = 1.0 - 2.0 * y; Lz = 1.0 - 2.0 * z; N[0] = 8; N[1] = 1; N[2] = 9; N[3] = 20; N[4] = 21; N[5] = 17; N[6] = 22; N[7] = 26; } else if ((x <= 0.5) && (y >= 0.5) && (z <= 0.5)) // T2 { Lx = 2.0 - 2.0 * x; Ly = 2.0 - 2.0 * y; Lz = 1.0 - 2.0 * z; N[0] = 20; N[1] = 9; N[2] = 2; N[3] = 10; N[4] = 26; N[5] = 22; N[6] = 18; N[7] = 23; } else if ((x >= 0.5) && (y >= 0.5) && (z <= 0.5)) // T3 { Lx = 1.0 - 2.0 * x; Ly = 2.0 - 2.0 * y; Lz = 1.0 - 2.0 * z; N[0] = 11; N[1] = 20; N[2] = 10; N[3] = 3; N[4] = 24; N[5] = 26; N[6] = 23; N[7] = 19; } else if ((x <= 0.5) && (y <= 0.5) && (z >= 0.5)) // T4 { Lx = 1.0 - 2.0 * x; Ly = 1.0 - 2.0 * y; Lz = 2.0 - 2.0 * z; N[0] = 16; N[1] = 21; N[2] = 26; N[3] = 24; N[4] = 4; N[5] = 12; N[6] = 25; N[7] = 15; } else if ((x >= 0.5) && (y <= 0.5) && (z >= 0.5)) // T5 { Lx = 2.0 - 2.0 * x; Ly = 1.0 - 2.0 * y; Lz = 2.0 - 2.0 * z; N[0] = 21; N[1] = 17; N[2] = 22; N[3] = 26; N[4] = 12; N[5] = 5; N[6] = 13; N[7] = 25; } else if ((x <= 0.5) && (y >= 0.5) && (z >= 0.5)) // T6 { Lx = 2.0 - 2.0 * x; Ly = 2.0 - 2.0 * y; Lz = 2.0 - 2.0 * z; N[0] = 26; N[1] = 22; N[2] = 18; N[3] = 23; N[4] = 25; N[5] = 13; N[6] = 6; N[7] = 14; } else // T7 { Lx = 1.0 - 2.0 * x; Ly = 2.0 - 2.0 * y; Lz = 2.0 - 2.0 * z; N[0] = 24; N[1] = 26; N[2] = 23; N[3] = 19; N[4] = 15; N[5] = 25; N[6] = 14; N[7] = 7; } dshape(N[0],0) = -2.0 * Ly * Lz ; dshape(N[0],1) = -2.0 * Lx * Lz ; dshape(N[0],2) = -2.0 * Lx * Ly ; dshape(N[1],0) = 2.0 * Ly * Lz ; dshape(N[1],1) = -2.0 * (1 - Lx) * Lz ; dshape(N[1],2) = -2.0 * (1 - Lx) * Ly ; dshape(N[2],0) = 2.0 * (1 - Ly) * Lz ; dshape(N[2],1) = 2.0 * (1 - Lx) * Lz ; dshape(N[2],2) = -2.0 * (1 - Lx) * (1 - Ly); dshape(N[3],0) = -2.0 * (1 - Ly) * Lz ; dshape(N[3],1) = 2.0 * Lx * Lz ; dshape(N[3],2) = -2.0 * Lx * (1 - Ly); dshape(N[4],0) = -2.0 * Ly * (1 - Lz); dshape(N[4],1) = -2.0 * Lx * (1 - Lz); dshape(N[4],2) = 2.0 * Lx * Ly ; dshape(N[5],0) = 2.0 * Ly * (1 - Lz); dshape(N[5],1) = -2.0 * (1 - Lx) * (1 - Lz); dshape(N[5],2) = 2.0 * (1 - Lx) * Ly ; dshape(N[6],0) = 2.0 * (1 - Ly) * (1 - Lz); dshape(N[6],1) = 2.0 * (1 - Lx) * (1 - Lz); dshape(N[6],2) = 2.0 * (1 - Lx) * (1 - Ly); dshape(N[7],0) = -2.0 * (1 - Ly) * (1 - Lz); dshape(N[7],1) = 2.0 * Lx * (1 - Lz); dshape(N[7],2) = 2.0 * Lx * (1 - Ly); } Nedelec1HexFiniteElement::Nedelec1HexFiniteElement() : VectorFiniteElement(3, Geometry::CUBE, 12, 1, H_CURL, FunctionSpace::Qk) { // not real nodes ... Nodes.IntPoint(0).x = 0.5; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(0).z = 0.0; Nodes.IntPoint(1).x = 1.0; Nodes.IntPoint(1).y = 0.5; Nodes.IntPoint(1).z = 0.0; Nodes.IntPoint(2).x = 0.5; Nodes.IntPoint(2).y = 1.0; Nodes.IntPoint(2).z = 0.0; Nodes.IntPoint(3).x = 0.0; Nodes.IntPoint(3).y = 0.5; Nodes.IntPoint(3).z = 0.0; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = 0.0; Nodes.IntPoint(4).z = 1.0; Nodes.IntPoint(5).x = 1.0; Nodes.IntPoint(5).y = 0.5; Nodes.IntPoint(5).z = 1.0; Nodes.IntPoint(6).x = 0.5; Nodes.IntPoint(6).y = 1.0; Nodes.IntPoint(6).z = 1.0; Nodes.IntPoint(7).x = 0.0; Nodes.IntPoint(7).y = 0.5; Nodes.IntPoint(7).z = 1.0; Nodes.IntPoint(8).x = 0.0; Nodes.IntPoint(8).y = 0.0; Nodes.IntPoint(8).z = 0.5; Nodes.IntPoint(9).x = 1.0; Nodes.IntPoint(9).y = 0.0; Nodes.IntPoint(9).z = 0.5; Nodes.IntPoint(10).x= 1.0; Nodes.IntPoint(10).y= 1.0; Nodes.IntPoint(10).z= 0.5; Nodes.IntPoint(11).x= 0.0; Nodes.IntPoint(11).y= 1.0; Nodes.IntPoint(11).z= 0.5; } void Nedelec1HexFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x = ip.x, y = ip.y, z = ip.z; shape(0,0) = (1. - y) * (1. - z); shape(0,1) = 0.; shape(0,2) = 0.; shape(2,0) = y * (1. - z); shape(2,1) = 0.; shape(2,2) = 0.; shape(4,0) = z * (1. - y); shape(4,1) = 0.; shape(4,2) = 0.; shape(6,0) = y * z; shape(6,1) = 0.; shape(6,2) = 0.; shape(1,0) = 0.; shape(1,1) = x * (1. - z); shape(1,2) = 0.; shape(3,0) = 0.; shape(3,1) = (1. - x) * (1. - z); shape(3,2) = 0.; shape(5,0) = 0.; shape(5,1) = x * z; shape(5,2) = 0.; shape(7,0) = 0.; shape(7,1) = (1. - x) * z; shape(7,2) = 0.; shape(8,0) = 0.; shape(8,1) = 0.; shape(8,2) = (1. - x) * (1. - y); shape(9,0) = 0.; shape(9,1) = 0.; shape(9,2) = x * (1. - y); shape(10,0) = 0.; shape(10,1) = 0.; shape(10,2) = x * y; shape(11,0) = 0.; shape(11,1) = 0.; shape(11,2) = y * (1. - x); } void Nedelec1HexFiniteElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { double x = ip.x, y = ip.y, z = ip.z; curl_shape(0,0) = 0.; curl_shape(0,1) = y - 1.; curl_shape(0,2) = 1. - z; curl_shape(2,0) = 0.; curl_shape(2,1) = -y; curl_shape(2,2) = z - 1.; curl_shape(4,0) = 0; curl_shape(4,1) = 1. - y; curl_shape(4,2) = z; curl_shape(6,0) = 0.; curl_shape(6,1) = y; curl_shape(6,2) = -z; curl_shape(1,0) = x; curl_shape(1,1) = 0.; curl_shape(1,2) = 1. - z; curl_shape(3,0) = 1. - x; curl_shape(3,1) = 0.; curl_shape(3,2) = z - 1.; curl_shape(5,0) = -x; curl_shape(5,1) = 0.; curl_shape(5,2) = z; curl_shape(7,0) = x - 1.; curl_shape(7,1) = 0.; curl_shape(7,2) = -z; curl_shape(8,0) = x - 1.; curl_shape(8,1) = 1. - y; curl_shape(8,2) = 0.; curl_shape(9,0) = -x; curl_shape(9,1) = y - 1.; curl_shape(9,2) = 0; curl_shape(10,0) = x; curl_shape(10,1) = -y; curl_shape(10,2) = 0.; curl_shape(11,0) = 1. - x; curl_shape(11,1) = y; curl_shape(11,2) = 0.; } const double Nedelec1HexFiniteElement::tk[12][3] = { {1,0,0}, {0,1,0}, {1,0,0}, {0,1,0}, {1,0,0}, {0,1,0}, {1,0,0}, {0,1,0}, {0,0,1}, {0,0,1}, {0,0,1}, {0,0,1} }; void Nedelec1HexFiniteElement::GetLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I) const { int k, j; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); #endif #ifdef MFEM_DEBUG for (k = 0; k < 12; k++) { CalcVShape (Nodes.IntPoint(k), vshape); for (j = 0; j < 12; j++) { double d = ( vshape(j,0)*tk[k][0] + vshape(j,1)*tk[k][1] + vshape(j,2)*tk[k][2] ); if (j == k) { d -= 1.0; } if (fabs(d) > 1.0e-12) { mfem::err << "Nedelec1HexFiniteElement::GetLocalInterpolation (...)\n" " k = " << k << ", j = " << j << ", d = " << d << endl; mfem_error(); } } } #endif IntegrationPoint ip; ip.x = ip.y = ip.z = 0.0; Trans.SetIntPoint (&ip); // Trans must be linear (more to have embedding?) const DenseMatrix &J = Trans.Jacobian(); double vk[3]; Vector xk (vk, 3); for (k = 0; k < 12; k++) { Trans.Transform (Nodes.IntPoint (k), xk); ip.x = vk[0]; ip.y = vk[1]; ip.z = vk[2]; CalcVShape (ip, vshape); // vk = J tk vk[0] = J(0,0)*tk[k][0]+J(0,1)*tk[k][1]+J(0,2)*tk[k][2]; vk[1] = J(1,0)*tk[k][0]+J(1,1)*tk[k][1]+J(1,2)*tk[k][2]; vk[2] = J(2,0)*tk[k][0]+J(2,1)*tk[k][1]+J(2,2)*tk[k][2]; for (j = 0; j < 12; j++) if (fabs (I(k,j) = (vshape(j,0)*vk[0]+vshape(j,1)*vk[1]+ vshape(j,2)*vk[2])) < 1.0e-12) { I(k,j) = 0.0; } } } void Nedelec1HexFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[3]; Vector xk (vk, 3); for (int k = 0; k < 12; k++) { Trans.SetIntPoint (&Nodes.IntPoint (k)); const DenseMatrix &J = Trans.Jacobian(); vc.Eval (xk, Trans, Nodes.IntPoint (k)); // xk^t J tk dofs(k) = vk[0] * ( J(0,0)*tk[k][0]+J(0,1)*tk[k][1]+J(0,2)*tk[k][2] ) + vk[1] * ( J(1,0)*tk[k][0]+J(1,1)*tk[k][1]+J(1,2)*tk[k][2] ) + vk[2] * ( J(2,0)*tk[k][0]+J(2,1)*tk[k][1]+J(2,2)*tk[k][2] ); } } Nedelec1TetFiniteElement::Nedelec1TetFiniteElement() : VectorFiniteElement(3, Geometry::TETRAHEDRON, 6, 1, H_CURL) { // not real nodes ... Nodes.IntPoint(0).x = 0.5; Nodes.IntPoint(0).y = 0.0; Nodes.IntPoint(0).z = 0.0; Nodes.IntPoint(1).x = 0.0; Nodes.IntPoint(1).y = 0.5; Nodes.IntPoint(1).z = 0.0; Nodes.IntPoint(2).x = 0.0; Nodes.IntPoint(2).y = 0.0; Nodes.IntPoint(2).z = 0.5; Nodes.IntPoint(3).x = 0.5; Nodes.IntPoint(3).y = 0.5; Nodes.IntPoint(3).z = 0.0; Nodes.IntPoint(4).x = 0.5; Nodes.IntPoint(4).y = 0.0; Nodes.IntPoint(4).z = 0.5; Nodes.IntPoint(5).x = 0.0; Nodes.IntPoint(5).y = 0.5; Nodes.IntPoint(5).z = 0.5; } void Nedelec1TetFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x = ip.x, y = ip.y, z = ip.z; shape(0,0) = 1. - y - z; shape(0,1) = x; shape(0,2) = x; shape(1,0) = y; shape(1,1) = 1. - x - z; shape(1,2) = y; shape(2,0) = z; shape(2,1) = z; shape(2,2) = 1. - x - y; shape(3,0) = -y; shape(3,1) = x; shape(3,2) = 0.; shape(4,0) = -z; shape(4,1) = 0.; shape(4,2) = x; shape(5,0) = 0.; shape(5,1) = -z; shape(5,2) = y; } void Nedelec1TetFiniteElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { curl_shape(0,0) = 0.; curl_shape(0,1) = -2.; curl_shape(0,2) = 2.; curl_shape(1,0) = 2.; curl_shape(1,1) = 0.; curl_shape(1,2) = -2.; curl_shape(2,0) = -2.; curl_shape(2,1) = 2.; curl_shape(2,2) = 0.; curl_shape(3,0) = 0.; curl_shape(3,1) = 0.; curl_shape(3,2) = 2.; curl_shape(4,0) = 0.; curl_shape(4,1) = -2.; curl_shape(4,2) = 0.; curl_shape(5,0) = 2.; curl_shape(5,1) = 0.; curl_shape(5,2) = 0.; } const double Nedelec1TetFiniteElement::tk[6][3] = {{1,0,0}, {0,1,0}, {0,0,1}, {-1,1,0}, {-1,0,1}, {0,-1,1}}; void Nedelec1TetFiniteElement::GetLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I) const { int k, j; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); #endif #ifdef MFEM_DEBUG for (k = 0; k < 6; k++) { CalcVShape (Nodes.IntPoint(k), vshape); for (j = 0; j < 6; j++) { double d = ( vshape(j,0)*tk[k][0] + vshape(j,1)*tk[k][1] + vshape(j,2)*tk[k][2] ); if (j == k) { d -= 1.0; } if (fabs(d) > 1.0e-12) { mfem::err << "Nedelec1TetFiniteElement::GetLocalInterpolation (...)\n" " k = " << k << ", j = " << j << ", d = " << d << endl; mfem_error(); } } } #endif IntegrationPoint ip; ip.x = ip.y = ip.z = 0.0; Trans.SetIntPoint (&ip); // Trans must be linear const DenseMatrix &J = Trans.Jacobian(); double vk[3]; Vector xk (vk, 3); for (k = 0; k < 6; k++) { Trans.Transform (Nodes.IntPoint (k), xk); ip.x = vk[0]; ip.y = vk[1]; ip.z = vk[2]; CalcVShape (ip, vshape); // vk = J tk vk[0] = J(0,0)*tk[k][0]+J(0,1)*tk[k][1]+J(0,2)*tk[k][2]; vk[1] = J(1,0)*tk[k][0]+J(1,1)*tk[k][1]+J(1,2)*tk[k][2]; vk[2] = J(2,0)*tk[k][0]+J(2,1)*tk[k][1]+J(2,2)*tk[k][2]; for (j = 0; j < 6; j++) if (fabs (I(k,j) = (vshape(j,0)*vk[0]+vshape(j,1)*vk[1]+ vshape(j,2)*vk[2])) < 1.0e-12) { I(k,j) = 0.0; } } } void Nedelec1TetFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[3]; Vector xk (vk, 3); for (int k = 0; k < 6; k++) { Trans.SetIntPoint (&Nodes.IntPoint (k)); const DenseMatrix &J = Trans.Jacobian(); vc.Eval (xk, Trans, Nodes.IntPoint (k)); // xk^t J tk dofs(k) = vk[0] * ( J(0,0)*tk[k][0]+J(0,1)*tk[k][1]+J(0,2)*tk[k][2] ) + vk[1] * ( J(1,0)*tk[k][0]+J(1,1)*tk[k][1]+J(1,2)*tk[k][2] ) + vk[2] * ( J(2,0)*tk[k][0]+J(2,1)*tk[k][1]+J(2,2)*tk[k][2] ); } } RT0HexFiniteElement::RT0HexFiniteElement() : VectorFiniteElement(3, Geometry::CUBE, 6, 1, H_DIV, FunctionSpace::Qk) { // not real nodes ... // z = 0, y = 0, x = 1, y = 1, x = 0, z = 1 Nodes.IntPoint(0).x = 0.5; Nodes.IntPoint(0).y = 0.5; Nodes.IntPoint(0).z = 0.0; Nodes.IntPoint(1).x = 0.5; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(1).z = 0.5; Nodes.IntPoint(2).x = 1.0; Nodes.IntPoint(2).y = 0.5; Nodes.IntPoint(2).z = 0.5; Nodes.IntPoint(3).x = 0.5; Nodes.IntPoint(3).y = 1.0; Nodes.IntPoint(3).z = 0.5; Nodes.IntPoint(4).x = 0.0; Nodes.IntPoint(4).y = 0.5; Nodes.IntPoint(4).z = 0.5; Nodes.IntPoint(5).x = 0.5; Nodes.IntPoint(5).y = 0.5; Nodes.IntPoint(5).z = 1.0; } void RT0HexFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x = ip.x, y = ip.y, z = ip.z; // z = 0 shape(0,0) = 0.; shape(0,1) = 0.; shape(0,2) = z - 1.; // y = 0 shape(1,0) = 0.; shape(1,1) = y - 1.; shape(1,2) = 0.; // x = 1 shape(2,0) = x; shape(2,1) = 0.; shape(2,2) = 0.; // y = 1 shape(3,0) = 0.; shape(3,1) = y; shape(3,2) = 0.; // x = 0 shape(4,0) = x - 1.; shape(4,1) = 0.; shape(4,2) = 0.; // z = 1 shape(5,0) = 0.; shape(5,1) = 0.; shape(5,2) = z; } void RT0HexFiniteElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { divshape(0) = 1.; divshape(1) = 1.; divshape(2) = 1.; divshape(3) = 1.; divshape(4) = 1.; divshape(5) = 1.; } const double RT0HexFiniteElement::nk[6][3] = {{0,0,-1}, {0,-1,0}, {1,0,0}, {0,1,0}, {-1,0,0}, {0,0,1}}; void RT0HexFiniteElement::GetLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I) const { int k, j; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG for (k = 0; k < 6; k++) { CalcVShape (Nodes.IntPoint(k), vshape); for (j = 0; j < 6; j++) { double d = ( vshape(j,0)*nk[k][0] + vshape(j,1)*nk[k][1] + vshape(j,2)*nk[k][2] ); if (j == k) { d -= 1.0; } if (fabs(d) > 1.0e-12) { mfem::err << "RT0HexFiniteElement::GetLocalInterpolation (...)\n" " k = " << k << ", j = " << j << ", d = " << d << endl; mfem_error(); } } } #endif IntegrationPoint ip; ip.x = ip.y = ip.z = 0.0; Trans.SetIntPoint (&ip); // Trans must be linear // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); double vk[3]; Vector xk (vk, 3); for (k = 0; k < 6; k++) { Trans.Transform (Nodes.IntPoint (k), xk); ip.x = vk[0]; ip.y = vk[1]; ip.z = vk[2]; CalcVShape (ip, vshape); // vk = |J| J^{-t} nk vk[0] = Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]+Jinv(0,2)*nk[k][2]; vk[1] = Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]+Jinv(1,2)*nk[k][2]; vk[2] = Jinv(2,0)*nk[k][0]+Jinv(2,1)*nk[k][1]+Jinv(2,2)*nk[k][2]; for (j = 0; j < 6; j++) if (fabs (I(k,j) = (vshape(j,0)*vk[0]+vshape(j,1)*vk[1]+ vshape(j,2)*vk[2])) < 1.0e-12) { I(k,j) = 0.0; } } } void RT0HexFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[3]; Vector xk (vk, 3); #ifdef MFEM_THREAD_SAFE DenseMatrix Jinv(dim); #endif for (int k = 0; k < 6; k++) { Trans.SetIntPoint (&Nodes.IntPoint (k)); // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); vc.Eval (xk, Trans, Nodes.IntPoint (k)); // xk^t |J| J^{-t} nk dofs(k) = vk[0] * ( Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]+Jinv(0,2)*nk[k][2] ) + vk[1] * ( Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]+Jinv(1,2)*nk[k][2] ) + vk[2] * ( Jinv(2,0)*nk[k][0]+Jinv(2,1)*nk[k][1]+Jinv(2,2)*nk[k][2] ); } } RT1HexFiniteElement::RT1HexFiniteElement() : VectorFiniteElement(3, Geometry::CUBE, 36, 2, H_DIV, FunctionSpace::Qk) { // z = 0 Nodes.IntPoint(2).x = 1./3.; Nodes.IntPoint(2).y = 1./3.; Nodes.IntPoint(2).z = 0.0; Nodes.IntPoint(3).x = 2./3.; Nodes.IntPoint(3).y = 1./3.; Nodes.IntPoint(3).z = 0.0; Nodes.IntPoint(0).x = 1./3.; Nodes.IntPoint(0).y = 2./3.; Nodes.IntPoint(0).z = 0.0; Nodes.IntPoint(1).x = 2./3.; Nodes.IntPoint(1).y = 2./3.; Nodes.IntPoint(1).z = 0.0; // y = 0 Nodes.IntPoint(4).x = 1./3.; Nodes.IntPoint(4).y = 0.0; Nodes.IntPoint(4).z = 1./3.; Nodes.IntPoint(5).x = 2./3.; Nodes.IntPoint(5).y = 0.0; Nodes.IntPoint(5).z = 1./3.; Nodes.IntPoint(6).x = 1./3.; Nodes.IntPoint(6).y = 0.0; Nodes.IntPoint(6).z = 2./3.; Nodes.IntPoint(7).x = 2./3.; Nodes.IntPoint(7).y = 0.0; Nodes.IntPoint(7).z = 2./3.; // x = 1 Nodes.IntPoint(8).x = 1.0; Nodes.IntPoint(8).y = 1./3.; Nodes.IntPoint(8).z = 1./3.; Nodes.IntPoint(9).x = 1.0; Nodes.IntPoint(9).y = 2./3.; Nodes.IntPoint(9).z = 1./3.; Nodes.IntPoint(10).x = 1.0; Nodes.IntPoint(10).y = 1./3.; Nodes.IntPoint(10).z = 2./3.; Nodes.IntPoint(11).x = 1.0; Nodes.IntPoint(11).y = 2./3.; Nodes.IntPoint(11).z = 2./3.; // y = 1 Nodes.IntPoint(13).x = 1./3.; Nodes.IntPoint(13).y = 1.0; Nodes.IntPoint(13).z = 1./3.; Nodes.IntPoint(12).x = 2./3.; Nodes.IntPoint(12).y = 1.0; Nodes.IntPoint(12).z = 1./3.; Nodes.IntPoint(15).x = 1./3.; Nodes.IntPoint(15).y = 1.0; Nodes.IntPoint(15).z = 2./3.; Nodes.IntPoint(14).x = 2./3.; Nodes.IntPoint(14).y = 1.0; Nodes.IntPoint(14).z = 2./3.; // x = 0 Nodes.IntPoint(17).x = 0.0; Nodes.IntPoint(17).y = 1./3.; Nodes.IntPoint(17).z = 1./3.; Nodes.IntPoint(16).x = 0.0; Nodes.IntPoint(16).y = 2./3.; Nodes.IntPoint(16).z = 1./3.; Nodes.IntPoint(19).x = 0.0; Nodes.IntPoint(19).y = 1./3.; Nodes.IntPoint(19).z = 2./3.; Nodes.IntPoint(18).x = 0.0; Nodes.IntPoint(18).y = 2./3.; Nodes.IntPoint(18).z = 2./3.; // z = 1 Nodes.IntPoint(20).x = 1./3.; Nodes.IntPoint(20).y = 1./3.; Nodes.IntPoint(20).z = 1.0; Nodes.IntPoint(21).x = 2./3.; Nodes.IntPoint(21).y = 1./3.; Nodes.IntPoint(21).z = 1.0; Nodes.IntPoint(22).x = 1./3.; Nodes.IntPoint(22).y = 2./3.; Nodes.IntPoint(22).z = 1.0; Nodes.IntPoint(23).x = 2./3.; Nodes.IntPoint(23).y = 2./3.; Nodes.IntPoint(23).z = 1.0; // x = 0.5 (interior) Nodes.IntPoint(24).x = 0.5; Nodes.IntPoint(24).y = 1./3.; Nodes.IntPoint(24).z = 1./3.; Nodes.IntPoint(25).x = 0.5; Nodes.IntPoint(25).y = 1./3.; Nodes.IntPoint(25).z = 2./3.; Nodes.IntPoint(26).x = 0.5; Nodes.IntPoint(26).y = 2./3.; Nodes.IntPoint(26).z = 1./3.; Nodes.IntPoint(27).x = 0.5; Nodes.IntPoint(27).y = 2./3.; Nodes.IntPoint(27).z = 2./3.; // y = 0.5 (interior) Nodes.IntPoint(28).x = 1./3.; Nodes.IntPoint(28).y = 0.5; Nodes.IntPoint(28).z = 1./3.; Nodes.IntPoint(29).x = 1./3.; Nodes.IntPoint(29).y = 0.5; Nodes.IntPoint(29).z = 2./3.; Nodes.IntPoint(30).x = 2./3.; Nodes.IntPoint(30).y = 0.5; Nodes.IntPoint(30).z = 1./3.; Nodes.IntPoint(31).x = 2./3.; Nodes.IntPoint(31).y = 0.5; Nodes.IntPoint(31).z = 2./3.; // z = 0.5 (interior) Nodes.IntPoint(32).x = 1./3.; Nodes.IntPoint(32).y = 1./3.; Nodes.IntPoint(32).z = 0.5; Nodes.IntPoint(33).x = 1./3.; Nodes.IntPoint(33).y = 2./3.; Nodes.IntPoint(33).z = 0.5; Nodes.IntPoint(34).x = 2./3.; Nodes.IntPoint(34).y = 1./3.; Nodes.IntPoint(34).z = 0.5; Nodes.IntPoint(35).x = 2./3.; Nodes.IntPoint(35).y = 2./3.; Nodes.IntPoint(35).z = 0.5; } void RT1HexFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x = ip.x, y = ip.y, z = ip.z; // z = 0 shape(2,0) = 0.; shape(2,1) = 0.; shape(2,2) = -(1. - 3.*z + 2.*z*z)*( 2. - 3.*x)*( 2. - 3.*y); shape(3,0) = 0.; shape(3,1) = 0.; shape(3,2) = -(1. - 3.*z + 2.*z*z)*(-1. + 3.*x)*( 2. - 3.*y); shape(0,0) = 0.; shape(0,1) = 0.; shape(0,2) = -(1. - 3.*z + 2.*z*z)*( 2. - 3.*x)*(-1. + 3.*y); shape(1,0) = 0.; shape(1,1) = 0.; shape(1,2) = -(1. - 3.*z + 2.*z*z)*(-1. + 3.*x)*(-1. + 3.*y); // y = 0 shape(4,0) = 0.; shape(4,1) = -(1. - 3.*y + 2.*y*y)*( 2. - 3.*x)*( 2. - 3.*z); shape(4,2) = 0.; shape(5,0) = 0.; shape(5,1) = -(1. - 3.*y + 2.*y*y)*(-1. + 3.*x)*( 2. - 3.*z); shape(5,2) = 0.; shape(6,0) = 0.; shape(6,1) = -(1. - 3.*y + 2.*y*y)*( 2. - 3.*x)*(-1. + 3.*z); shape(6,2) = 0.; shape(7,0) = 0.; shape(7,1) = -(1. - 3.*y + 2.*y*y)*(-1. + 3.*x)*(-1. + 3.*z); shape(7,2) = 0.; // x = 1 shape(8,0) = (-x + 2.*x*x)*( 2. - 3.*y)*( 2. - 3.*z); shape(8,1) = 0.; shape(8,2) = 0.; shape(9,0) = (-x + 2.*x*x)*(-1. + 3.*y)*( 2. - 3.*z); shape(9,1) = 0.; shape(9,2) = 0.; shape(10,0) = (-x + 2.*x*x)*( 2. - 3.*y)*(-1. + 3.*z); shape(10,1) = 0.; shape(10,2) = 0.; shape(11,0) = (-x + 2.*x*x)*(-1. + 3.*y)*(-1. + 3.*z); shape(11,1) = 0.; shape(11,2) = 0.; // y = 1 shape(13,0) = 0.; shape(13,1) = (-y + 2.*y*y)*( 2. - 3.*x)*( 2. - 3.*z); shape(13,2) = 0.; shape(12,0) = 0.; shape(12,1) = (-y + 2.*y*y)*(-1. + 3.*x)*( 2. - 3.*z); shape(12,2) = 0.; shape(15,0) = 0.; shape(15,1) = (-y + 2.*y*y)*( 2. - 3.*x)*(-1. + 3.*z); shape(15,2) = 0.; shape(14,0) = 0.; shape(14,1) = (-y + 2.*y*y)*(-1. + 3.*x)*(-1. + 3.*z); shape(14,2) = 0.; // x = 0 shape(17,0) = -(1. - 3.*x + 2.*x*x)*( 2. - 3.*y)*( 2. - 3.*z); shape(17,1) = 0.; shape(17,2) = 0.; shape(16,0) = -(1. - 3.*x + 2.*x*x)*(-1. + 3.*y)*( 2. - 3.*z); shape(16,1) = 0.; shape(16,2) = 0.; shape(19,0) = -(1. - 3.*x + 2.*x*x)*( 2. - 3.*y)*(-1. + 3.*z); shape(19,1) = 0.; shape(19,2) = 0.; shape(18,0) = -(1. - 3.*x + 2.*x*x)*(-1. + 3.*y)*(-1. + 3.*z); shape(18,1) = 0.; shape(18,2) = 0.; // z = 1 shape(20,0) = 0.; shape(20,1) = 0.; shape(20,2) = (-z + 2.*z*z)*( 2. - 3.*x)*( 2. - 3.*y); shape(21,0) = 0.; shape(21,1) = 0.; shape(21,2) = (-z + 2.*z*z)*(-1. + 3.*x)*( 2. - 3.*y); shape(22,0) = 0.; shape(22,1) = 0.; shape(22,2) = (-z + 2.*z*z)*( 2. - 3.*x)*(-1. + 3.*y); shape(23,0) = 0.; shape(23,1) = 0.; shape(23,2) = (-z + 2.*z*z)*(-1. + 3.*x)*(-1. + 3.*y); // x = 0.5 (interior) shape(24,0) = (4.*x - 4.*x*x)*( 2. - 3.*y)*( 2. - 3.*z); shape(24,1) = 0.; shape(24,2) = 0.; shape(25,0) = (4.*x - 4.*x*x)*( 2. - 3.*y)*(-1. + 3.*z); shape(25,1) = 0.; shape(25,2) = 0.; shape(26,0) = (4.*x - 4.*x*x)*(-1. + 3.*y)*( 2. - 3.*z); shape(26,1) = 0.; shape(26,2) = 0.; shape(27,0) = (4.*x - 4.*x*x)*(-1. + 3.*y)*(-1. + 3.*z); shape(27,1) = 0.; shape(27,2) = 0.; // y = 0.5 (interior) shape(28,0) = 0.; shape(28,1) = (4.*y - 4.*y*y)*( 2. - 3.*x)*( 2. - 3.*z); shape(28,2) = 0.; shape(29,0) = 0.; shape(29,1) = (4.*y - 4.*y*y)*( 2. - 3.*x)*(-1. + 3.*z); shape(29,2) = 0.; shape(30,0) = 0.; shape(30,1) = (4.*y - 4.*y*y)*(-1. + 3.*x)*( 2. - 3.*z); shape(30,2) = 0.; shape(31,0) = 0.; shape(31,1) = (4.*y - 4.*y*y)*(-1. + 3.*x)*(-1. + 3.*z); shape(31,2) = 0.; // z = 0.5 (interior) shape(32,0) = 0.; shape(32,1) = 0.; shape(32,2) = (4.*z - 4.*z*z)*( 2. - 3.*x)*( 2. - 3.*y); shape(33,0) = 0.; shape(33,1) = 0.; shape(33,2) = (4.*z - 4.*z*z)*( 2. - 3.*x)*(-1. + 3.*y); shape(34,0) = 0.; shape(34,1) = 0.; shape(34,2) = (4.*z - 4.*z*z)*(-1. + 3.*x)*( 2. - 3.*y); shape(35,0) = 0.; shape(35,1) = 0.; shape(35,2) = (4.*z - 4.*z*z)*(-1. + 3.*x)*(-1. + 3.*y); } void RT1HexFiniteElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { double x = ip.x, y = ip.y, z = ip.z; // z = 0 divshape(2) = -(-3. + 4.*z)*( 2. - 3.*x)*( 2. - 3.*y); divshape(3) = -(-3. + 4.*z)*(-1. + 3.*x)*( 2. - 3.*y); divshape(0) = -(-3. + 4.*z)*( 2. - 3.*x)*(-1. + 3.*y); divshape(1) = -(-3. + 4.*z)*(-1. + 3.*x)*(-1. + 3.*y); // y = 0 divshape(4) = -(-3. + 4.*y)*( 2. - 3.*x)*( 2. - 3.*z); divshape(5) = -(-3. + 4.*y)*(-1. + 3.*x)*( 2. - 3.*z); divshape(6) = -(-3. + 4.*y)*( 2. - 3.*x)*(-1. + 3.*z); divshape(7) = -(-3. + 4.*y)*(-1. + 3.*x)*(-1. + 3.*z); // x = 1 divshape(8) = (-1. + 4.*x)*( 2. - 3.*y)*( 2. - 3.*z); divshape(9) = (-1. + 4.*x)*(-1. + 3.*y)*( 2. - 3.*z); divshape(10) = (-1. + 4.*x)*( 2. - 3.*y)*(-1. + 3.*z); divshape(11) = (-1. + 4.*x)*(-1. + 3.*y)*(-1. + 3.*z); // y = 1 divshape(13) = (-1. + 4.*y)*( 2. - 3.*x)*( 2. - 3.*z); divshape(12) = (-1. + 4.*y)*(-1. + 3.*x)*( 2. - 3.*z); divshape(15) = (-1. + 4.*y)*( 2. - 3.*x)*(-1. + 3.*z); divshape(14) = (-1. + 4.*y)*(-1. + 3.*x)*(-1. + 3.*z); // x = 0 divshape(17) = -(-3. + 4.*x)*( 2. - 3.*y)*( 2. - 3.*z); divshape(16) = -(-3. + 4.*x)*(-1. + 3.*y)*( 2. - 3.*z); divshape(19) = -(-3. + 4.*x)*( 2. - 3.*y)*(-1. + 3.*z); divshape(18) = -(-3. + 4.*x)*(-1. + 3.*y)*(-1. + 3.*z); // z = 1 divshape(20) = (-1. + 4.*z)*( 2. - 3.*x)*( 2. - 3.*y); divshape(21) = (-1. + 4.*z)*(-1. + 3.*x)*( 2. - 3.*y); divshape(22) = (-1. + 4.*z)*( 2. - 3.*x)*(-1. + 3.*y); divshape(23) = (-1. + 4.*z)*(-1. + 3.*x)*(-1. + 3.*y); // x = 0.5 (interior) divshape(24) = ( 4. - 8.*x)*( 2. - 3.*y)*( 2. - 3.*z); divshape(25) = ( 4. - 8.*x)*( 2. - 3.*y)*(-1. + 3.*z); divshape(26) = ( 4. - 8.*x)*(-1. + 3.*y)*( 2. - 3.*z); divshape(27) = ( 4. - 8.*x)*(-1. + 3.*y)*(-1. + 3.*z); // y = 0.5 (interior) divshape(28) = ( 4. - 8.*y)*( 2. - 3.*x)*( 2. - 3.*z); divshape(29) = ( 4. - 8.*y)*( 2. - 3.*x)*(-1. + 3.*z); divshape(30) = ( 4. - 8.*y)*(-1. + 3.*x)*( 2. - 3.*z); divshape(31) = ( 4. - 8.*y)*(-1. + 3.*x)*(-1. + 3.*z); // z = 0.5 (interior) divshape(32) = ( 4. - 8.*z)*( 2. - 3.*x)*( 2. - 3.*y); divshape(33) = ( 4. - 8.*z)*( 2. - 3.*x)*(-1. + 3.*y); divshape(34) = ( 4. - 8.*z)*(-1. + 3.*x)*( 2. - 3.*y); divshape(35) = ( 4. - 8.*z)*(-1. + 3.*x)*(-1. + 3.*y); } const double RT1HexFiniteElement::nk[36][3] = { {0, 0,-1}, {0, 0,-1}, {0, 0,-1}, {0, 0,-1}, {0,-1, 0}, {0,-1, 0}, {0,-1, 0}, {0,-1, 0}, {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {-1,0, 0}, {-1,0, 0}, {-1,0, 0}, {-1,0, 0}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, {1, 0, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 1, 0}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1}, {0, 0, 1} }; void RT1HexFiniteElement::GetLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I) const { int k, j; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG for (k = 0; k < 36; k++) { CalcVShape (Nodes.IntPoint(k), vshape); for (j = 0; j < 36; j++) { double d = ( vshape(j,0)*nk[k][0] + vshape(j,1)*nk[k][1] + vshape(j,2)*nk[k][2] ); if (j == k) { d -= 1.0; } if (fabs(d) > 1.0e-12) { mfem::err << "RT0HexFiniteElement::GetLocalInterpolation (...)\n" " k = " << k << ", j = " << j << ", d = " << d << endl; mfem_error(); } } } #endif IntegrationPoint ip; ip.x = ip.y = ip.z = 0.0; Trans.SetIntPoint (&ip); // Trans must be linear // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); double vk[3]; Vector xk (vk, 3); for (k = 0; k < 36; k++) { Trans.Transform (Nodes.IntPoint (k), xk); ip.x = vk[0]; ip.y = vk[1]; ip.z = vk[2]; CalcVShape (ip, vshape); // vk = |J| J^{-t} nk vk[0] = Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]+Jinv(0,2)*nk[k][2]; vk[1] = Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]+Jinv(1,2)*nk[k][2]; vk[2] = Jinv(2,0)*nk[k][0]+Jinv(2,1)*nk[k][1]+Jinv(2,2)*nk[k][2]; for (j = 0; j < 36; j++) if (fabs (I(k,j) = (vshape(j,0)*vk[0]+vshape(j,1)*vk[1]+ vshape(j,2)*vk[2])) < 1.0e-12) { I(k,j) = 0.0; } } } void RT1HexFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[3]; Vector xk (vk, 3); #ifdef MFEM_THREAD_SAFE DenseMatrix Jinv(dim); #endif for (int k = 0; k < 36; k++) { Trans.SetIntPoint (&Nodes.IntPoint (k)); // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); vc.Eval (xk, Trans, Nodes.IntPoint (k)); // xk^t |J| J^{-t} nk dofs(k) = vk[0] * ( Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]+Jinv(0,2)*nk[k][2] ) + vk[1] * ( Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]+Jinv(1,2)*nk[k][2] ) + vk[2] * ( Jinv(2,0)*nk[k][0]+Jinv(2,1)*nk[k][1]+Jinv(2,2)*nk[k][2] ); } } RT0TetFiniteElement::RT0TetFiniteElement() : VectorFiniteElement(3, Geometry::TETRAHEDRON, 4, 1, H_DIV) { // not real nodes ... Nodes.IntPoint(0).x = 0.33333333333333333333; Nodes.IntPoint(0).y = 0.33333333333333333333; Nodes.IntPoint(0).z = 0.33333333333333333333; Nodes.IntPoint(1).x = 0.0; Nodes.IntPoint(1).y = 0.33333333333333333333; Nodes.IntPoint(1).z = 0.33333333333333333333; Nodes.IntPoint(2).x = 0.33333333333333333333; Nodes.IntPoint(2).y = 0.0; Nodes.IntPoint(2).z = 0.33333333333333333333; Nodes.IntPoint(3).x = 0.33333333333333333333; Nodes.IntPoint(3).y = 0.33333333333333333333; Nodes.IntPoint(3).z = 0.0; } void RT0TetFiniteElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { double x2 = 2.0*ip.x, y2 = 2.0*ip.y, z2 = 2.0*ip.z; shape(0,0) = x2; shape(0,1) = y2; shape(0,2) = z2; shape(1,0) = x2 - 2.0; shape(1,1) = y2; shape(1,2) = z2; shape(2,0) = x2; shape(2,1) = y2 - 2.0; shape(2,2) = z2; shape(3,0) = x2; shape(3,1) = y2; shape(3,2) = z2 - 2.0; } void RT0TetFiniteElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { divshape(0) = 6.0; divshape(1) = 6.0; divshape(2) = 6.0; divshape(3) = 6.0; } const double RT0TetFiniteElement::nk[4][3] = {{.5,.5,.5}, {-.5,0,0}, {0,-.5,0}, {0,0,-.5}}; void RT0TetFiniteElement::GetLocalInterpolation ( ElementTransformation &Trans, DenseMatrix &I) const { int k, j; #ifdef MFEM_THREAD_SAFE DenseMatrix vshape(dof, dim); DenseMatrix Jinv(dim); #endif #ifdef MFEM_DEBUG for (k = 0; k < 4; k++) { CalcVShape (Nodes.IntPoint(k), vshape); for (j = 0; j < 4; j++) { double d = ( vshape(j,0)*nk[k][0] + vshape(j,1)*nk[k][1] + vshape(j,2)*nk[k][2] ); if (j == k) { d -= 1.0; } if (fabs(d) > 1.0e-12) { mfem::err << "RT0TetFiniteElement::GetLocalInterpolation (...)\n" " k = " << k << ", j = " << j << ", d = " << d << endl; mfem_error(); } } } #endif IntegrationPoint ip; ip.x = ip.y = ip.z = 0.0; Trans.SetIntPoint (&ip); // Trans must be linear // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); double vk[3]; Vector xk (vk, 3); for (k = 0; k < 4; k++) { Trans.Transform (Nodes.IntPoint (k), xk); ip.x = vk[0]; ip.y = vk[1]; ip.z = vk[2]; CalcVShape (ip, vshape); // vk = |J| J^{-t} nk vk[0] = Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]+Jinv(0,2)*nk[k][2]; vk[1] = Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]+Jinv(1,2)*nk[k][2]; vk[2] = Jinv(2,0)*nk[k][0]+Jinv(2,1)*nk[k][1]+Jinv(2,2)*nk[k][2]; for (j = 0; j < 4; j++) if (fabs (I(k,j) = (vshape(j,0)*vk[0]+vshape(j,1)*vk[1]+ vshape(j,2)*vk[2])) < 1.0e-12) { I(k,j) = 0.0; } } } void RT0TetFiniteElement::Project ( VectorCoefficient &vc, ElementTransformation &Trans, Vector &dofs) const { double vk[3]; Vector xk (vk, 3); #ifdef MFEM_THREAD_SAFE DenseMatrix Jinv(dim); #endif for (int k = 0; k < 4; k++) { Trans.SetIntPoint (&Nodes.IntPoint (k)); // set Jinv = |J| J^{-t} = adj(J)^t CalcAdjugateTranspose (Trans.Jacobian(), Jinv); vc.Eval (xk, Trans, Nodes.IntPoint (k)); // xk^t |J| J^{-t} nk dofs(k) = vk[0] * ( Jinv(0,0)*nk[k][0]+Jinv(0,1)*nk[k][1]+Jinv(0,2)*nk[k][2] ) + vk[1] * ( Jinv(1,0)*nk[k][0]+Jinv(1,1)*nk[k][1]+Jinv(1,2)*nk[k][2] ) + vk[2] * ( Jinv(2,0)*nk[k][0]+Jinv(2,1)*nk[k][1]+Jinv(2,2)*nk[k][2] ); } } RotTriLinearHexFiniteElement::RotTriLinearHexFiniteElement() : NodalFiniteElement(3, Geometry::CUBE, 6, 2, FunctionSpace::Qk) { Nodes.IntPoint(0).x = 0.5; Nodes.IntPoint(0).y = 0.5; Nodes.IntPoint(0).z = 0.0; Nodes.IntPoint(1).x = 0.5; Nodes.IntPoint(1).y = 0.0; Nodes.IntPoint(1).z = 0.5; Nodes.IntPoint(2).x = 1.0; Nodes.IntPoint(2).y = 0.5; Nodes.IntPoint(2).z = 0.5; Nodes.IntPoint(3).x = 0.5; Nodes.IntPoint(3).y = 1.0; Nodes.IntPoint(3).z = 0.5; Nodes.IntPoint(4).x = 0.0; Nodes.IntPoint(4).y = 0.5; Nodes.IntPoint(4).z = 0.5; Nodes.IntPoint(5).x = 0.5; Nodes.IntPoint(5).y = 0.5; Nodes.IntPoint(5).z = 1.0; } void RotTriLinearHexFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { double x = 2. * ip.x - 1.; double y = 2. * ip.y - 1.; double z = 2. * ip.z - 1.; double f5 = x * x - y * y; double f6 = y * y - z * z; shape(0) = (1./6.) * (1. - 3. * z - f5 - 2. * f6); shape(1) = (1./6.) * (1. - 3. * y - f5 + f6); shape(2) = (1./6.) * (1. + 3. * x + 2. * f5 + f6); shape(3) = (1./6.) * (1. + 3. * y - f5 + f6); shape(4) = (1./6.) * (1. - 3. * x + 2. * f5 + f6); shape(5) = (1./6.) * (1. + 3. * z - f5 - 2. * f6); } void RotTriLinearHexFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { const double a = 2./3.; double xt = a * (1. - 2. * ip.x); double yt = a * (1. - 2. * ip.y); double zt = a * (1. - 2. * ip.z); dshape(0,0) = xt; dshape(0,1) = yt; dshape(0,2) = -1. - 2. * zt; dshape(1,0) = xt; dshape(1,1) = -1. - 2. * yt; dshape(1,2) = zt; dshape(2,0) = 1. - 2. * xt; dshape(2,1) = yt; dshape(2,2) = zt; dshape(3,0) = xt; dshape(3,1) = 1. - 2. * yt; dshape(3,2) = zt; dshape(4,0) = -1. - 2. * xt; dshape(4,1) = yt; dshape(4,2) = zt; dshape(5,0) = xt; dshape(5,1) = yt; dshape(5,2) = 1. - 2. * zt; } Poly_1D::Basis::Basis(const int p, const double *nodes, EvalType etype) : etype(etype) { switch (etype) { case ChangeOfBasis: { x.SetSize(p + 1); w.SetSize(p + 1); DenseMatrix A(p + 1); for (int i = 0; i <= p; i++) { CalcBasis(p, nodes[i], A.GetColumn(i)); } Ai.Factor(A); // mfem::out << "Poly_1D::Basis(" << p << ",...) : "; Ai.TestInversion(); break; } case Barycentric: { x.SetSize(p + 1); w.SetSize(p + 1); x = nodes; w = 1.0; for (int i = 0; i <= p; i++) { for (int j = 0; j < i; j++) { double xij = x(i) - x(j); w(i) *= xij; w(j) *= -xij; } } for (int i = 0; i <= p; i++) { w(i) = 1.0/w(i); } #ifdef MFEM_DEBUG // Make sure the nodes are increasing for (int i = 0; i < p; i++) { if (x(i) >= x(i+1)) { mfem_error("Poly_1D::Basis::Basis : nodes are not increasing!"); } } #endif break; } case Positive: x.SetDataAndSize(NULL, p + 1); // use x to store (p + 1) break; default: break; } } void Poly_1D::Basis::Eval(const double y, Vector &u) const { switch (etype) { case ChangeOfBasis: { CalcBasis(Ai.Width() - 1, y, x); Ai.Mult(x, u); break; } case Barycentric: { int i, k, p = x.Size() - 1; double l, lk; if (p == 0) { u(0) = 1.0; return; } lk = 1.0; for (k = 0; k < p; k++) { if (y >= (x(k) + x(k+1))/2) { lk *= y - x(k); } else { for (i = k+1; i <= p; i++) { lk *= y - x(i); } break; } } l = lk * (y - x(k)); for (i = 0; i < k; i++) { u(i) = l * w(i) / (y - x(i)); } u(k) = lk * w(k); for (i++; i <= p; i++) { u(i) = l * w(i) / (y - x(i)); } break; } case Positive: CalcBernstein(x.Size() - 1, y, u); break; default: break; } } void Poly_1D::Basis::Eval(const double y, Vector &u, Vector &d) const { switch (etype) { case ChangeOfBasis: { CalcBasis(Ai.Width() - 1, y, x, w); Ai.Mult(x, u); Ai.Mult(w, d); break; } case Barycentric: { int i, k, p = x.Size() - 1; double l, lp, lk, sk, si; if (p == 0) { u(0) = 1.0; d(0) = 0.0; return; } lk = 1.0; for (k = 0; k < p; k++) { if (y >= (x(k) + x(k+1))/2) { lk *= y - x(k); } else { for (i = k+1; i <= p; i++) { lk *= y - x(i); } break; } } l = lk * (y - x(k)); sk = 0.0; for (i = 0; i < k; i++) { si = 1.0/(y - x(i)); sk += si; u(i) = l * si * w(i); } u(k) = lk * w(k); for (i++; i <= p; i++) { si = 1.0/(y - x(i)); sk += si; u(i) = l * si * w(i); } lp = l * sk + lk; for (i = 0; i < k; i++) { d(i) = (lp * w(i) - u(i))/(y - x(i)); } d(k) = sk * u(k); for (i++; i <= p; i++) { d(i) = (lp * w(i) - u(i))/(y - x(i)); } break; } case Positive: CalcBernstein(x.Size() - 1, y, u, d); break; default: break; } } const int *Poly_1D::Binom(const int p) { if (binom.NumCols() <= p) { binom.SetSize(p + 1, p + 1); for (int i = 0; i <= p; i++) { binom(i,0) = binom(i,i) = 1; for (int j = 1; j < i; j++) { binom(i,j) = binom(i-1,j) + binom(i-1,j-1); } } } return binom[p]; } void Poly_1D::ChebyshevPoints(const int p, double *x) { for (int i = 0; i <= p; i++) { // x[i] = 0.5*(1. + cos(M_PI*(p - i + 0.5)/(p + 1))); double s = sin(M_PI_2*(i + 0.5)/(p + 1)); x[i] = s*s; } } void Poly_1D::CalcMono(const int p, const double x, double *u) { double xn; u[0] = xn = 1.; for (int n = 1; n <= p; n++) { u[n] = (xn *= x); } } void Poly_1D::CalcMono(const int p, const double x, double *u, double *d) { double xn; u[0] = xn = 1.; d[0] = 0.; for (int n = 1; n <= p; n++) { d[n] = n * xn; u[n] = (xn *= x); } } void Poly_1D::CalcBinomTerms(const int p, const double x, const double y, double *u) { if (p == 0) { u[0] = 1.; } else { int i; const int *b = Binom(p); double z = x; for (i = 1; i < p; i++) { u[i] = b[i]*z; z *= x; } u[p] = z; z = y; for (i--; i > 0; i--) { u[i] *= z; z *= y; } u[0] = z; } } void Poly_1D::CalcBinomTerms(const int p, const double x, const double y, double *u, double *d) { if (p == 0) { u[0] = 1.; d[0] = 0.; } else { int i; const int *b = Binom(p); const double xpy = x + y, ptx = p*x; double z = 1.; for (i = 1; i < p; i++) { d[i] = b[i]*z*(i*xpy - ptx); z *= x; u[i] = b[i]*z; } d[p] = p*z; u[p] = z*x; z = 1.; for (i--; i > 0; i--) { d[i] *= z; z *= y; u[i] *= z; } d[0] = -p*z; u[0] = z*y; } } void Poly_1D::CalcDBinomTerms(const int p, const double x, const double y, double *d) { if (p == 0) { d[0] = 0.; } else { int i; const int *b = Binom(p); const double xpy = x + y, ptx = p*x; double z = 1.; for (i = 1; i < p; i++) { d[i] = b[i]*z*(i*xpy - ptx); z *= x; } d[p] = p*z; z = 1.; for (i--; i > 0; i--) { d[i] *= z; z *= y; } d[0] = -p*z; } } void Poly_1D::CalcLegendre(const int p, const double x, double *u) { // use the recursive definition for [-1,1]: // (n+1)*P_{n+1}(z) = (2*n+1)*z*P_n(z)-n*P_{n-1}(z) double z; u[0] = 1.; if (p == 0) { return; } u[1] = z = 2.*x - 1.; for (int n = 1; n < p; n++) { u[n+1] = ((2*n + 1)*z*u[n] - n*u[n-1])/(n + 1); } } void Poly_1D::CalcLegendre(const int p, const double x, double *u, double *d) { // use the recursive definition for [-1,1]: // (n+1)*P_{n+1}(z) = (2*n+1)*z*P_n(z)-n*P_{n-1}(z) // for the derivative use, z in [-1,1]: // P'_{n+1}(z) = (2*n+1)*P_n(z)+P'_{n-1}(z) double z; u[0] = 1.; d[0] = 0.; if (p == 0) { return; } u[1] = z = 2.*x - 1.; d[1] = 2.; for (int n = 1; n < p; n++) { u[n+1] = ((2*n + 1)*z*u[n] - n*u[n-1])/(n + 1); d[n+1] = (4*n + 2)*u[n] + d[n-1]; } } void Poly_1D::CalcChebyshev(const int p, const double x, double *u) { // recursive definition, z in [-1,1] // T_0(z) = 1, T_1(z) = z // T_{n+1}(z) = 2*z*T_n(z) - T_{n-1}(z) double z; u[0] = 1.; if (p == 0) { return; } u[1] = z = 2.*x - 1.; for (int n = 1; n < p; n++) { u[n+1] = 2*z*u[n] - u[n-1]; } } void Poly_1D::CalcChebyshev(const int p, const double x, double *u, double *d) { // recursive definition, z in [-1,1] // T_0(z) = 1, T_1(z) = z // T_{n+1}(z) = 2*z*T_n(z) - T_{n-1}(z) // T'_n(z) = n*U_{n-1}(z) // U_0(z) = 1 U_1(z) = 2*z // U_{n+1}(z) = 2*z*U_n(z) - U_{n-1}(z) // U_n(z) = z*U_{n-1}(z) + T_n(z) = z*T'_n(z)/n + T_n(z) // T'_{n+1}(z) = (n + 1)*(z*T'_n(z)/n + T_n(z)) double z; u[0] = 1.; d[0] = 0.; if (p == 0) { return; } u[1] = z = 2.*x - 1.; d[1] = 2.; for (int n = 1; n < p; n++) { u[n+1] = 2*z*u[n] - u[n-1]; d[n+1] = (n + 1)*(z*d[n]/n + 2*u[n]); } } void Poly_1D::CalcChebyshev(const int p, const double x, double *u, double *d, double *dd) { // recursive definition, z in [-1,1] // T_0(z) = 1, T_1(z) = z // T_{n+1}(z) = 2*z*T_n(z) - T_{n-1}(z) // T'_n(z) = n*U_{n-1}(z) // U_0(z) = 1 U_1(z) = 2*z // U_{n+1}(z) = 2*z*U_n(z) - U_{n-1}(z) // U_n(z) = z*U_{n-1}(z) + T_n(z) = z*T'_n(z)/n + T_n(z) // T'_{n+1}(z) = (n + 1)*(z*T'_n(z)/n + T_n(z)) // T''_{n+1}(z) = (n + 1)*(2*(n + 1)*T'_n(z) + z*T''_n(z)) / n double z; u[0] = 1.; d[0] = 0.; dd[0]= 0.; if (p == 0) { return; } u[1] = z = 2.*x - 1.; d[1] = 2.; dd[1] = 0; for (int n = 1; n < p; n++) { u[n+1] = 2*z*u[n] - u[n-1]; d[n+1] = (n + 1)*(z*d[n]/n + 2*u[n]); dd[n+1] = (n + 1)*(2.*(n + 1)*d[n] + z*dd[n])/n; } } const double *Poly_1D::GetPoints(const int p, const int btype) { BasisType::Check(btype); const int qtype = BasisType::GetQuadrature1D(btype); if (qtype == Quadrature1D::Invalid) { return NULL; } if (points_container.find(btype) == points_container.end()) { points_container[btype] = new Array(h_mt); } Array &pts = *points_container[btype]; if (pts.Size() <= p) { pts.SetSize(p + 1, NULL); } if (pts[p] == NULL) { pts[p] = new double[p + 1]; quad_func.GivePolyPoints(p+1, pts[p], qtype); } return pts[p]; } Poly_1D::Basis &Poly_1D::GetBasis(const int p, const int btype) { BasisType::Check(btype); if ( bases_container.find(btype) == bases_container.end() ) { // we haven't been asked for basis or points of this type yet bases_container[btype] = new Array(h_mt); } Array &bases = *bases_container[btype]; if (bases.Size() <= p) { bases.SetSize(p + 1, NULL); } if (bases[p] == NULL) { EvalType etype = (btype == BasisType::Positive) ? Positive : Barycentric; bases[p] = new Basis(p, GetPoints(p, btype), etype); } return *bases[p]; } Poly_1D::~Poly_1D() { for (PointsMap::iterator it = points_container.begin(); it != points_container.end() ; ++it) { Array& pts = *it->second; for ( int i = 0 ; i < pts.Size() ; ++i ) { delete [] pts[i]; } delete it->second; } for (BasisMap::iterator it = bases_container.begin(); it != bases_container.end() ; ++it) { Array& bases = *it->second; for ( int i = 0 ; i < bases.Size() ; ++i ) { delete bases[i]; } delete it->second; } } Array2D Poly_1D::binom; Poly_1D poly1d; TensorBasisElement::TensorBasisElement(const int dims, const int p, const int btype, const DofMapType dmtype) : b_type(btype), basis1d(poly1d.GetBasis(p, b_type)) { if (dmtype == H1_DOF_MAP || dmtype == Sr_DOF_MAP) { switch (dims) { case 1: { dof_map.SetSize(p + 1); dof_map[0] = 0; dof_map[p] = 1; for (int i = 1; i < p; i++) { dof_map[i] = i+1; } break; } case 2: { const int p1 = p + 1; dof_map.SetSize(p1*p1); // vertices dof_map[0 + 0*p1] = 0; dof_map[p + 0*p1] = 1; dof_map[p + p*p1] = 2; dof_map[0 + p*p1] = 3; // edges int o = 4; for (int i = 1; i < p; i++) { dof_map[i + 0*p1] = o++; } for (int i = 1; i < p; i++) { dof_map[p + i*p1] = o++; } for (int i = 1; i < p; i++) { dof_map[(p-i) + p*p1] = o++; } for (int i = 1; i < p; i++) { dof_map[0 + (p-i)*p1] = o++; } // interior for (int j = 1; j < p; j++) { for (int i = 1; i < p; i++) { dof_map[i + j*p1] = o++; } } break; } case 3: { const int p1 = p + 1; dof_map.SetSize(p1*p1*p1); // vertices dof_map[0 + (0 + 0*p1)*p1] = 0; dof_map[p + (0 + 0*p1)*p1] = 1; dof_map[p + (p + 0*p1)*p1] = 2; dof_map[0 + (p + 0*p1)*p1] = 3; dof_map[0 + (0 + p*p1)*p1] = 4; dof_map[p + (0 + p*p1)*p1] = 5; dof_map[p + (p + p*p1)*p1] = 6; dof_map[0 + (p + p*p1)*p1] = 7; // edges (see Hexahedron::edges in mesh/hexahedron.cpp). // edges (see Constants::Edges in fem/geom.cpp). int o = 8; for (int i = 1; i < p; i++) { dof_map[i + (0 + 0*p1)*p1] = o++; // (0,1) } for (int i = 1; i < p; i++) { dof_map[p + (i + 0*p1)*p1] = o++; // (1,2) } for (int i = 1; i < p; i++) { dof_map[i + (p + 0*p1)*p1] = o++; // (3,2) } for (int i = 1; i < p; i++) { dof_map[0 + (i + 0*p1)*p1] = o++; // (0,3) } for (int i = 1; i < p; i++) { dof_map[i + (0 + p*p1)*p1] = o++; // (4,5) } for (int i = 1; i < p; i++) { dof_map[p + (i + p*p1)*p1] = o++; // (5,6) } for (int i = 1; i < p; i++) { dof_map[i + (p + p*p1)*p1] = o++; // (7,6) } for (int i = 1; i < p; i++) { dof_map[0 + (i + p*p1)*p1] = o++; // (4,7) } for (int i = 1; i < p; i++) { dof_map[0 + (0 + i*p1)*p1] = o++; // (0,4) } for (int i = 1; i < p; i++) { dof_map[p + (0 + i*p1)*p1] = o++; // (1,5) } for (int i = 1; i < p; i++) { dof_map[p + (p + i*p1)*p1] = o++; // (2,6) } for (int i = 1; i < p; i++) { dof_map[0 + (p + i*p1)*p1] = o++; // (3,7) } // faces (see Mesh::GenerateFaces in mesh/mesh.cpp) for (int j = 1; j < p; j++) { for (int i = 1; i < p; i++) { dof_map[i + ((p-j) + 0*p1)*p1] = o++; // (3,2,1,0) } } for (int j = 1; j < p; j++) { for (int i = 1; i < p; i++) { dof_map[i + (0 + j*p1)*p1] = o++; // (0,1,5,4) } } for (int j = 1; j < p; j++) { for (int i = 1; i < p; i++) { dof_map[p + (i + j*p1)*p1] = o++; // (1,2,6,5) } } for (int j = 1; j < p; j++) { for (int i = 1; i < p; i++) { dof_map[(p-i) + (p + j*p1)*p1] = o++; // (2,3,7,6) } } for (int j = 1; j < p; j++) { for (int i = 1; i < p; i++) { dof_map[0 + ((p-i) + j*p1)*p1] = o++; // (3,0,4,7) } } for (int j = 1; j < p; j++) { for (int i = 1; i < p; i++) { dof_map[i + (j + p*p1)*p1] = o++; // (4,5,6,7) } } // interior for (int k = 1; k < p; k++) { for (int j = 1; j < p; j++) { for (int i = 1; i < p; i++) { dof_map[i + (j + k*p1)*p1] = o++; } } } break; } default: MFEM_ABORT("invalid dimension: " << dims); break; } } else if (dmtype == L2_DOF_MAP) { // leave dof_map empty, indicating that the dofs are ordered // lexicographically, i.e. the dof_map is identity } else { MFEM_ABORT("invalid DofMapType: " << dmtype); } } NodalTensorFiniteElement::NodalTensorFiniteElement(const int dims, const int p, const int btype, const DofMapType dmtype) : NodalFiniteElement(dims, GetTensorProductGeometry(dims), Pow(p + 1, dims), p, dims > 1 ? FunctionSpace::Qk : FunctionSpace::Pk), TensorBasisElement(dims, p, VerifyNodal(btype), dmtype) { } PositiveTensorFiniteElement::PositiveTensorFiniteElement( const int dims, const int p, const DofMapType dmtype) : PositiveFiniteElement(dims, GetTensorProductGeometry(dims), Pow(p + 1, dims), p, dims > 1 ? FunctionSpace::Qk : FunctionSpace::Pk), TensorBasisElement(dims, p, BasisType::Positive, dmtype) { } VectorTensorFiniteElement::VectorTensorFiniteElement(const int dims, const int d, const int p, const int cbtype, const int obtype, const int M, const DofMapType dmtype) : VectorFiniteElement(dims, GetTensorProductGeometry(dims), d, p, M, FunctionSpace::Qk), TensorBasisElement(dims, p, VerifyNodal(cbtype), dmtype), cbasis1d(poly1d.GetBasis(p, VerifyClosed(cbtype))), obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(obtype))) { } 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); #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::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); #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::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); #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::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; } } H1Pos_SegmentElement::H1Pos_SegmentElement(const int p) : PositiveTensorFiniteElement(1, p, H1_DOF_MAP) { #ifndef MFEM_THREAD_SAFE // thread private versions; see class header. shape_x.SetSize(p+1); dshape_x.SetSize(p+1); #endif // Endpoints need to be first in the list, so reorder them. Nodes.IntPoint(0).x = 0.0; Nodes.IntPoint(1).x = 1.0; for (int i = 1; i < p; i++) { Nodes.IntPoint(i+1).x = double(i)/p; } } void H1Pos_SegmentElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_x(p+1); #endif Poly_1D::CalcBernstein(p, ip.x, shape_x.GetData() ); // Endpoints need to be first in the list, so reorder them. shape(0) = shape_x(0); shape(1) = shape_x(p); for (int i = 1; i < p; i++) { shape(i+1) = shape_x(i); } } void H1Pos_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 Poly_1D::CalcBernstein(p, ip.x, shape_x.GetData(), dshape_x.GetData() ); // Endpoints need to be first in the list, so reorder them. 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 H1Pos_SegmentElement::ProjectDelta(int vertex, Vector &dofs) const { dofs = 0.0; dofs[vertex] = 1.0; } H1Pos_QuadrilateralElement::H1Pos_QuadrilateralElement(const int p) : PositiveTensorFiniteElement(2, p, H1_DOF_MAP) { #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); #endif int o = 0; for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { Nodes.IntPoint(dof_map[o++]).Set2(double(i)/p, double(j)/p); } } void H1Pos_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 Poly_1D::CalcBernstein(p, ip.x, shape_x.GetData() ); Poly_1D::CalcBernstein(p, ip.y, shape_y.GetData() ); // Reorder so that vertices are at the beginning of the list 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 H1Pos_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 Poly_1D::CalcBernstein(p, ip.x, shape_x.GetData(), dshape_x.GetData() ); Poly_1D::CalcBernstein(p, ip.y, shape_y.GetData(), dshape_y.GetData() ); // Reorder so that vertices are at the beginning of the list 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 H1Pos_QuadrilateralElement::ProjectDelta(int vertex, Vector &dofs) const { dofs = 0.0; dofs[vertex] = 1.0; } H1Pos_HexahedronElement::H1Pos_HexahedronElement(const int p) : PositiveTensorFiniteElement(3, p, H1_DOF_MAP) { #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); #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(double(i)/p, double(j)/p, double(k)/p); } void H1Pos_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 Poly_1D::CalcBernstein(p, ip.x, shape_x.GetData() ); Poly_1D::CalcBernstein(p, ip.y, shape_y.GetData() ); Poly_1D::CalcBernstein(p, ip.z, shape_z.GetData() ); 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 H1Pos_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 Poly_1D::CalcBernstein(p, ip.x, shape_x.GetData(), dshape_x.GetData() ); Poly_1D::CalcBernstein(p, ip.y, shape_y.GetData(), dshape_y.GetData() ); Poly_1D::CalcBernstein(p, ip.z, shape_z.GetData(), dshape_z.GetData() ); 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 H1Pos_HexahedronElement::ProjectDelta(int vertex, Vector &dofs) const { dofs = 0.0; dofs[vertex] = 1.0; } 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 // vertices Nodes.IntPoint(0).Set2(cp[0], cp[0]); Nodes.IntPoint(1).Set2(cp[p], cp[0]); Nodes.IntPoint(2).Set2(cp[0], cp[p]); // edges int o = 3; for (int i = 1; i < p; i++) { Nodes.IntPoint(o++).Set2(cp[i], cp[0]); } for (int i = 1; i < p; i++) { Nodes.IntPoint(o++).Set2(cp[p-i], cp[i]); } for (int i = 1; i < p; i++) { 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]; 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 // vertices Nodes.IntPoint(0).Set3(cp[0], cp[0], cp[0]); Nodes.IntPoint(1).Set3(cp[p], cp[0], cp[0]); Nodes.IntPoint(2).Set3(cp[0], cp[p], cp[0]); 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) { Nodes.IntPoint(o++).Set3(cp[i], cp[0], cp[0]); } for (int i = 1; i < p; i++) // (0,2) { Nodes.IntPoint(o++).Set3(cp[0], cp[i], cp[0]); } for (int i = 1; i < p; i++) // (0,3) { Nodes.IntPoint(o++).Set3(cp[0], cp[0], cp[i]); } for (int i = 1; i < p; i++) // (1,2) { Nodes.IntPoint(o++).Set3(cp[p-i], cp[i], cp[0]); } for (int i = 1; i < p; i++) // (1,3) { Nodes.IntPoint(o++).Set3(cp[p-i], cp[0], cp[i]); } for (int i = 1; i < p; i++) // (2,3) { 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) { 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) { 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) { 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) { 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++) { 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); } H1Pos_TriangleElement::H1Pos_TriangleElement(const int p) : PositiveFiniteElement(2, Geometry::TRIANGLE, ((p + 1)*(p + 2))/2, p, FunctionSpace::Pk) { #ifndef MFEM_THREAD_SAFE m_shape.SetSize(dof); dshape_1d.SetSize(p + 1); m_dshape.SetSize(dof, dim); #endif dof_map.SetSize(dof); struct Index { int p2p3; Index(int p) { p2p3 = 2*p + 3; } int operator()(int i, int j) { return ((p2p3-j)*j)/2+i; } }; Index idx(p); // vertices dof_map[idx(0,0)] = 0; Nodes.IntPoint(0).Set2(0., 0.); dof_map[idx(p,0)] = 1; Nodes.IntPoint(1).Set2(1., 0.); dof_map[idx(0,p)] = 2; Nodes.IntPoint(2).Set2(0., 1.); // edges int o = 3; for (int i = 1; i < p; i++) { dof_map[idx(i,0)] = o; Nodes.IntPoint(o++).Set2(double(i)/p, 0.); } for (int i = 1; i < p; i++) { dof_map[idx(p-i,i)] = o; Nodes.IntPoint(o++).Set2(double(p-i)/p, double(i)/p); } for (int i = 1; i < p; i++) { dof_map[idx(0,p-i)] = o; Nodes.IntPoint(o++).Set2(0., double(p-i)/p); } // interior for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) { dof_map[idx(i,j)] = o; Nodes.IntPoint(o++).Set2(double(i)/p, double(j)/p); } } // static method void H1Pos_TriangleElement::CalcShape( const int p, const double l1, const double l2, double *shape) { const double l3 = 1. - l1 - l2; // The (i,j) basis function is given by: T(i,j,p-i-j) l1^i l2^j l3^{p-i-j}, // where T(i,j,k) = (i+j+k)! / (i! j! k!) // Another expression is given by the terms of the expansion: // (l1 + l2 + l3)^p = // \sum_{j=0}^p \binom{p}{j} l2^j // \sum_{i=0}^{p-j} \binom{p-j}{i} l1^i l3^{p-j-i} const int *bp = Poly_1D::Binom(p); double z = 1.; for (int o = 0, j = 0; j <= p; j++) { Poly_1D::CalcBinomTerms(p - j, l1, l3, &shape[o]); double s = bp[j]*z; for (int i = 0; i <= p - j; i++) { shape[o++] *= s; } z *= l2; } } // static method void H1Pos_TriangleElement::CalcDShape( const int p, const double l1, const double l2, double *dshape_1d, double *dshape) { const int dof = ((p + 1)*(p + 2))/2; const double l3 = 1. - l1 - l2; const int *bp = Poly_1D::Binom(p); double z = 1.; for (int o = 0, j = 0; j <= p; j++) { Poly_1D::CalcDBinomTerms(p - j, l1, l3, dshape_1d); double s = bp[j]*z; for (int i = 0; i <= p - j; i++) { dshape[o++] = s*dshape_1d[i]; } z *= l2; } z = 1.; for (int i = 0; i <= p; i++) { Poly_1D::CalcDBinomTerms(p - i, l2, l3, dshape_1d); double s = bp[i]*z; for (int o = i, j = 0; j <= p - i; j++) { dshape[dof + o] = s*dshape_1d[j]; o += p + 1 - j; } z *= l1; } } void H1Pos_TriangleElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { #ifdef MFEM_THREAD_SAFE Vector m_shape(dof); #endif CalcShape(order, ip.x, ip.y, m_shape.GetData()); for (int i = 0; i < dof; i++) { shape(dof_map[i]) = m_shape(i); } } void H1Pos_TriangleElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { #ifdef MFEM_THREAD_SAFE Vector dshape_1d(order + 1); DenseMatrix m_dshape(dof, dim); #endif CalcDShape(order, ip.x, ip.y, dshape_1d.GetData(), m_dshape.Data()); for (int d = 0; d < 2; d++) { for (int i = 0; i < dof; i++) { dshape(dof_map[i],d) = m_dshape(i,d); } } } H1Pos_TetrahedronElement::H1Pos_TetrahedronElement(const int p) : PositiveFiniteElement(3, Geometry::TETRAHEDRON, ((p + 1)*(p + 2)*(p + 3))/6, p, FunctionSpace::Pk) { #ifndef MFEM_THREAD_SAFE m_shape.SetSize(dof); dshape_1d.SetSize(p + 1); m_dshape.SetSize(dof, dim); #endif dof_map.SetSize(dof); struct Index { int p, dof; int tri(int k) { return (k*(k + 1))/2; } int tet(int k) { return (k*(k + 1)*(k + 2))/6; } Index(int p_) { p = p_; dof = tet(p + 1); } int operator()(int i, int j, int k) { return dof - tet(p - k) - tri(p + 1 - k - j) + i; } }; Index idx(p); // vertices dof_map[idx(0,0,0)] = 0; Nodes.IntPoint(0).Set3(0., 0., 0.); dof_map[idx(p,0,0)] = 1; Nodes.IntPoint(1).Set3(1., 0., 0.); dof_map[idx(0,p,0)] = 2; Nodes.IntPoint(2).Set3(0., 1., 0.); dof_map[idx(0,0,p)] = 3; Nodes.IntPoint(3).Set3(0., 0., 1.); // edges (see Tetrahedron::edges in mesh/tetrahedron.cpp) int o = 4; for (int i = 1; i < p; i++) // (0,1) { dof_map[idx(i,0,0)] = o; Nodes.IntPoint(o++).Set3(double(i)/p, 0., 0.); } for (int i = 1; i < p; i++) // (0,2) { dof_map[idx(0,i,0)] = o; Nodes.IntPoint(o++).Set3(0., double(i)/p, 0.); } for (int i = 1; i < p; i++) // (0,3) { dof_map[idx(0,0,i)] = o; Nodes.IntPoint(o++).Set3(0., 0., double(i)/p); } for (int i = 1; i < p; i++) // (1,2) { dof_map[idx(p-i,i,0)] = o; Nodes.IntPoint(o++).Set3(double(p-i)/p, double(i)/p, 0.); } for (int i = 1; i < p; i++) // (1,3) { dof_map[idx(p-i,0,i)] = o; Nodes.IntPoint(o++).Set3(double(p-i)/p, 0., double(i)/p); } for (int i = 1; i < p; i++) // (2,3) { dof_map[idx(0,p-i,i)] = o; Nodes.IntPoint(o++).Set3(0., double(p-i)/p, double(i)/p); } // 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) { dof_map[idx(p-i-j,i,j)] = o; Nodes.IntPoint(o++).Set3(double(p-i-j)/p, double(i)/p, double(j)/p); } for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (0,3,2) { dof_map[idx(0,j,i)] = o; Nodes.IntPoint(o++).Set3(0., double(j)/p, double(i)/p); } for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (0,1,3) { dof_map[idx(i,0,j)] = o; Nodes.IntPoint(o++).Set3(double(i)/p, 0., double(j)/p); } for (int j = 1; j < p; j++) for (int i = 1; i + j < p; i++) // (0,2,1) { dof_map[idx(j,i,0)] = o; Nodes.IntPoint(o++).Set3(double(j)/p, double(i)/p, 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++) { dof_map[idx(i,j,k)] = o; Nodes.IntPoint(o++).Set3(double(i)/p, double(j)/p, double(k)/p); } } // static method void H1Pos_TetrahedronElement::CalcShape( const int p, const double l1, const double l2, const double l3, double *shape) { const double l4 = 1. - l1 - l2 - l3; // The basis functions are the terms in the expansion: // (l1 + l2 + l3 + l4)^p = // \sum_{k=0}^p \binom{p}{k} l3^k // \sum_{j=0}^{p-k} \binom{p-k}{j} l2^j // \sum_{i=0}^{p-k-j} \binom{p-k-j}{i} l1^i l4^{p-k-j-i} const int *bp = Poly_1D::Binom(p); double l3k = 1.; for (int o = 0, k = 0; k <= p; k++) { const int *bpk = Poly_1D::Binom(p - k); const double ek = bp[k]*l3k; double l2j = 1.; for (int j = 0; j <= p - k; j++) { Poly_1D::CalcBinomTerms(p - k - j, l1, l4, &shape[o]); double ekj = ek*bpk[j]*l2j; for (int i = 0; i <= p - k - j; i++) { shape[o++] *= ekj; } l2j *= l2; } l3k *= l3; } } // static method void H1Pos_TetrahedronElement::CalcDShape( const int p, const double l1, const double l2, const double l3, double *dshape_1d, double *dshape) { const int dof = ((p + 1)*(p + 2)*(p + 3))/6; const double l4 = 1. - l1 - l2 - l3; // For the x derivatives, differentiate the terms of the expression: // \sum_{k=0}^p \binom{p}{k} l3^k // \sum_{j=0}^{p-k} \binom{p-k}{j} l2^j // \sum_{i=0}^{p-k-j} \binom{p-k-j}{i} l1^i l4^{p-k-j-i} const int *bp = Poly_1D::Binom(p); double l3k = 1.; for (int o = 0, k = 0; k <= p; k++) { const int *bpk = Poly_1D::Binom(p - k); const double ek = bp[k]*l3k; double l2j = 1.; for (int j = 0; j <= p - k; j++) { Poly_1D::CalcDBinomTerms(p - k - j, l1, l4, dshape_1d); double ekj = ek*bpk[j]*l2j; for (int i = 0; i <= p - k - j; i++) { dshape[o++] = dshape_1d[i]*ekj; } l2j *= l2; } l3k *= l3; } // For the y derivatives, differentiate the terms of the expression: // \sum_{k=0}^p \binom{p}{k} l3^k // \sum_{i=0}^{p-k} \binom{p-k}{i} l1^i // \sum_{j=0}^{p-k-i} \binom{p-k-i}{j} l2^j l4^{p-k-j-i} l3k = 1.; for (int ok = 0, k = 0; k <= p; k++) { const int *bpk = Poly_1D::Binom(p - k); const double ek = bp[k]*l3k; double l1i = 1.; for (int i = 0; i <= p - k; i++) { Poly_1D::CalcDBinomTerms(p - k - i, l2, l4, dshape_1d); double eki = ek*bpk[i]*l1i; int o = ok + i; for (int j = 0; j <= p - k - i; j++) { dshape[dof + o] = dshape_1d[j]*eki; o += p - k - j + 1; } l1i *= l1; } l3k *= l3; ok += ((p - k + 2)*(p - k + 1))/2; } // For the z derivatives, differentiate the terms of the expression: // \sum_{j=0}^p \binom{p}{j} l2^j // \sum_{i=0}^{p-j} \binom{p-j}{i} l1^i // \sum_{k=0}^{p-j-i} \binom{p-j-i}{k} l3^k l4^{p-k-j-i} double l2j = 1.; for (int j = 0; j <= p; j++) { const int *bpj = Poly_1D::Binom(p - j); const double ej = bp[j]*l2j; double l1i = 1.; for (int i = 0; i <= p - j; i++) { Poly_1D::CalcDBinomTerms(p - j - i, l3, l4, dshape_1d); double eji = ej*bpj[i]*l1i; int m = ((p + 2)*(p + 1))/2; int n = ((p - j + 2)*(p - j + 1))/2; for (int o = i, k = 0; k <= p - j - i; k++) { // m = ((p - k + 2)*(p - k + 1))/2; // n = ((p - k - j + 2)*(p - k - j + 1))/2; o += m; dshape[2*dof + o - n] = dshape_1d[k]*eji; m -= p - k + 1; n -= p - k - j + 1; } l1i *= l1; } l2j *= l2; } } void H1Pos_TetrahedronElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { #ifdef MFEM_THREAD_SAFE Vector m_shape(dof); #endif CalcShape(order, ip.x, ip.y, ip.z, m_shape.GetData()); for (int i = 0; i < dof; i++) { shape(dof_map[i]) = m_shape(i); } } void H1Pos_TetrahedronElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { #ifdef MFEM_THREAD_SAFE Vector dshape_1d(order + 1); DenseMatrix m_dshape(dof, dim); #endif CalcDShape(order, ip.x, ip.y, ip.z, dshape_1d.GetData(), m_dshape.Data()); for (int d = 0; d < 3; d++) { for (int i = 0; i < dof; i++) { dshape(dof_map[i],d) = m_dshape(i,d); } } } 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); // Nodal DoFs 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 ne = p-1; for (int i=1; i 0) ? poly1d.OpenPoints(p - 1) : NULL; const double *bop = poly1d.OpenPoints(p); #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); u.SetSize(dof, dim); divu.SetSize(dof); #else Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); #endif // edges int o = 0; for (int i = 0; i <= p; i++) // (0,1) { Nodes.IntPoint(o).Set2(bop[i], 0.); dof2nk[o++] = 0; } for (int i = 0; i <= p; i++) // (1,2) { Nodes.IntPoint(o).Set2(bop[p-i], bop[i]); dof2nk[o++] = 1; } for (int i = 0; i <= p; i++) // (2,0) { Nodes.IntPoint(o).Set2(0., bop[p-i]); dof2nk[o++] = 2; } // interior for (int j = 0; j < p; j++) for (int i = 0; i + j < p; i++) { double w = iop[i] + iop[j] + iop[p-1-i-j]; Nodes.IntPoint(o).Set2(iop[i]/w, iop[j]/w); dof2nk[o++] = 0; Nodes.IntPoint(o).Set2(iop[i]/w, iop[j]/w); dof2nk[o++] = 2; } DenseMatrix T(dof); for (int k = 0; k < dof; k++) { const 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); const double *n_k = nk + 2*dof2nk[k]; o = 0; for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) { double s = shape_x(i)*shape_y(j)*shape_l(p-i-j); T(o++, k) = s*n_k[0]; T(o++, k) = s*n_k[1]; } for (int i = 0; i <= p; i++) { double s = shape_x(i)*shape_y(p-i); T(o++, k) = s*((ip.x - c)*n_k[0] + (ip.y - c)*n_k[1]); } } Ti.Factor(T); // mfem::out << "RT_TriangleElement(" << p << ") : "; Ti.TestInversion(); } void RT_TriangleElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { const int p = order - 1; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_l(p + 1); DenseMatrix u(dof, dim); #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); int o = 0; for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) { double s = shape_x(i)*shape_y(j)*shape_l(p-i-j); u(o,0) = s; u(o,1) = 0; o++; u(o,0) = 0; u(o,1) = s; o++; } for (int i = 0; i <= p; i++) { double s = shape_x(i)*shape_y(p-i); u(o,0) = (ip.x - c)*s; u(o,1) = (ip.y - c)*s; o++; } Ti.Mult(u, shape); } void RT_TriangleElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { const int p = order - 1; #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 divu(dof); #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); int o = 0; for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) { int k = p - i - j; divu(o++) = (dshape_x(i)*shape_l(k) - shape_x(i)*dshape_l(k))*shape_y(j); divu(o++) = (dshape_y(j)*shape_l(k) - shape_y(j)*dshape_l(k))*shape_x(i); } for (int i = 0; i <= p; i++) { int j = p - i; divu(o++) = ((shape_x(i) + (ip.x - c)*dshape_x(i))*shape_y(j) + (shape_y(j) + (ip.y - c)*dshape_y(j))*shape_x(i)); } Ti.Mult(divu, divshape); } const double RT_TetrahedronElement::nk[12] = { 1,1,1, -1,0,0, 0,-1,0, 0,0,-1 }; // { .5,.5,.5, -.5,0,0, 0,-.5,0, 0,0,-.5}; // n_F |F| const double RT_TetrahedronElement::c = 1./4.; RT_TetrahedronElement::RT_TetrahedronElement(const int p) : VectorFiniteElement(3, Geometry::TETRAHEDRON, (p + 1)*(p + 2)*(p + 4)/2, p + 1, H_DIV, FunctionSpace::Pk), dof2nk(dof) { const double *iop = (p > 0) ? poly1d.OpenPoints(p - 1) : NULL; const double *bop = poly1d.OpenPoints(p); #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); u.SetSize(dof, dim); divu.SetSize(dof); #else Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); #endif int o = 0; // faces (see Mesh::GenerateFaces in mesh/mesh.cpp, // the constructor of H1_TetrahedronElement) for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) // (1,2,3) { double w = bop[i] + bop[j] + bop[p-i-j]; Nodes.IntPoint(o).Set3(bop[p-i-j]/w, bop[i]/w, bop[j]/w); dof2nk[o++] = 0; } for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) // (0,3,2) { double w = bop[i] + bop[j] + bop[p-i-j]; Nodes.IntPoint(o).Set3(0., bop[j]/w, bop[i]/w); dof2nk[o++] = 1; } for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) // (0,1,3) { double w = bop[i] + bop[j] + bop[p-i-j]; Nodes.IntPoint(o).Set3(bop[i]/w, 0., bop[j]/w); dof2nk[o++] = 2; } for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) // (0,2,1) { double w = bop[i] + bop[j] + bop[p-i-j]; Nodes.IntPoint(o).Set3(bop[j]/w, bop[i]/w, 0.); dof2nk[o++] = 3; } // interior for (int k = 0; k < p; k++) for (int j = 0; j + k < p; j++) for (int i = 0; i + j + k < p; i++) { double w = iop[i] + iop[j] + iop[k] + iop[p-1-i-j-k]; Nodes.IntPoint(o).Set3(iop[i]/w, iop[j]/w, iop[k]/w); dof2nk[o++] = 1; Nodes.IntPoint(o).Set3(iop[i]/w, iop[j]/w, iop[k]/w); dof2nk[o++] = 2; Nodes.IntPoint(o).Set3(iop[i]/w, iop[j]/w, iop[k]/w); dof2nk[o++] = 3; } DenseMatrix T(dof); for (int m = 0; m < dof; m++) { const 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); const double *nm = nk + 3*dof2nk[m]; 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++) { double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_l(p-i-j-k); T(o++, m) = s * nm[0]; T(o++, m) = s * nm[1]; T(o++, m) = s * nm[2]; } for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) { double s = shape_x(i)*shape_y(j)*shape_z(p-i-j); T(o++, m) = s*((ip.x - c)*nm[0] + (ip.y - c)*nm[1] + (ip.z - c)*nm[2]); } } Ti.Factor(T); // mfem::out << "RT_TetrahedronElement(" << p << ") : "; Ti.TestInversion(); } void RT_TetrahedronElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { const int p = order - 1; #ifdef MFEM_THREAD_SAFE Vector shape_x(p + 1), shape_y(p + 1), shape_z(p + 1), shape_l(p + 1); DenseMatrix u(dof, dim); #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); int 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++) { double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_l(p-i-j-k); u(o,0) = s; u(o,1) = 0; u(o,2) = 0; o++; u(o,0) = 0; u(o,1) = s; u(o,2) = 0; o++; u(o,0) = 0; u(o,1) = 0; u(o,2) = s; o++; } for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) { double s = shape_x(i)*shape_y(j)*shape_z(p-i-j); u(o,0) = (ip.x - c)*s; u(o,1) = (ip.y - c)*s; u(o,2) = (ip.z - c)*s; o++; } Ti.Mult(u, shape); } void RT_TetrahedronElement::CalcDivShape(const IntegrationPoint &ip, Vector &divshape) const { const int p = order - 1; #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 divu(dof); #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); int 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++) { int l = p - i - j - k; divu(o++) = (dshape_x(i)*shape_l(l) - shape_x(i)*dshape_l(l))*shape_y(j)*shape_z(k); divu(o++) = (dshape_y(j)*shape_l(l) - shape_y(j)*dshape_l(l))*shape_x(i)*shape_z(k); divu(o++) = (dshape_z(k)*shape_l(l) - shape_z(k)*dshape_l(l))*shape_x(i)*shape_y(j); } for (int j = 0; j <= p; j++) for (int i = 0; i + j <= p; i++) { int k = p - i - j; divu(o++) = (shape_x(i) + (ip.x - c)*dshape_x(i))*shape_y(j)*shape_z(k) + (shape_y(j) + (ip.y - c)*dshape_y(j))*shape_x(i)*shape_z(k) + (shape_z(k) + (ip.z - c)*dshape_z(k))*shape_x(i)*shape_y(j); } Ti.Mult(divu, divshape); } const double ND_HexahedronElement::tk[18] = { 1.,0.,0., 0.,1.,0., 0.,0.,1., -1.,0.,0., 0.,-1.,0., 0.,0.,-1. }; ND_HexahedronElement::ND_HexahedronElement(const int p, const int cb_type, const int ob_type) : VectorTensorFiniteElement(3, 3*p*(p + 1)*(p + 1), p, cb_type, ob_type, H_CURL, DofMapType::L2_DOF_MAP), dof2tk(dof) { dof_map.SetSize(dof); const double *cp = poly1d.ClosedPoints(p, cb_type); const double *op = poly1d.OpenPoints(p - 1, ob_type); const int dof3 = dof/3; #ifndef MFEM_THREAD_SAFE shape_cx.SetSize(p + 1); shape_ox.SetSize(p); shape_cy.SetSize(p + 1); shape_oy.SetSize(p); shape_cz.SetSize(p + 1); shape_oz.SetSize(p); dshape_cx.SetSize(p + 1); dshape_cy.SetSize(p + 1); dshape_cz.SetSize(p + 1); #endif // edges int o = 0; for (int i = 0; i < p; i++) // (0,1) { dof_map[0*dof3 + i + (0 + 0*(p + 1))*p] = o++; } for (int i = 0; i < p; i++) // (1,2) { dof_map[1*dof3 + p + (i + 0*p)*(p + 1)] = o++; } for (int i = 0; i < p; i++) // (3,2) { dof_map[0*dof3 + i + (p + 0*(p + 1))*p] = o++; } for (int i = 0; i < p; i++) // (0,3) { dof_map[1*dof3 + 0 + (i + 0*p)*(p + 1)] = o++; } for (int i = 0; i < p; i++) // (4,5) { dof_map[0*dof3 + i + (0 + p*(p + 1))*p] = o++; } for (int i = 0; i < p; i++) // (5,6) { dof_map[1*dof3 + p + (i + p*p)*(p + 1)] = o++; } for (int i = 0; i < p; i++) // (7,6) { dof_map[0*dof3 + i + (p + p*(p + 1))*p] = o++; } for (int i = 0; i < p; i++) // (4,7) { dof_map[1*dof3 + 0 + (i + p*p)*(p + 1)] = o++; } for (int i = 0; i < p; i++) // (0,4) { dof_map[2*dof3 + 0 + (0 + i*(p + 1))*(p + 1)] = o++; } for (int i = 0; i < p; i++) // (1,5) { dof_map[2*dof3 + p + (0 + i*(p + 1))*(p + 1)] = o++; } for (int i = 0; i < p; i++) // (2,6) { dof_map[2*dof3 + p + (p + i*(p + 1))*(p + 1)] = o++; } for (int i = 0; i < p; i++) // (3,7) { dof_map[2*dof3 + 0 + (p + i*(p + 1))*(p + 1)] = o++; } // faces // (3,2,1,0) -- bottom for (int j = 1; j < p; j++) // x - components for (int i = 0; i < p; i++) { dof_map[0*dof3 + i + ((p - j) + 0*(p + 1))*p] = o++; } for (int j = 0; j < p; j++) // y - components for (int i = 1; i < p; i++) { dof_map[1*dof3 + i + ((p - 1 - j) + 0*p)*(p + 1)] = -1 - (o++); } // (0,1,5,4) -- front for (int k = 1; k < p; k++) // x - components for (int i = 0; i < p; i++) { dof_map[0*dof3 + i + (0 + k*(p + 1))*p] = o++; } for (int k = 0; k < p; k++) // z - components for (int i = 1; i < p; i++ ) { dof_map[2*dof3 + i + (0 + k*(p + 1))*(p + 1)] = o++; } // (1,2,6,5) -- right for (int k = 1; k < p; k++) // y - components for (int j = 0; j < p; j++) { dof_map[1*dof3 + p + (j + k*p)*(p + 1)] = o++; } for (int k = 0; k < p; k++) // z - components for (int j = 1; j < p; j++) { dof_map[2*dof3 + p + (j + k*(p + 1))*(p + 1)] = o++; } // (2,3,7,6) -- back for (int k = 1; k < p; k++) // x - components for (int i = 0; i < p; i++) { dof_map[0*dof3 + (p - 1 - i) + (p + k*(p + 1))*p] = -1 - (o++); } for (int k = 0; k < p; k++) // z - components for (int i = 1; i < p; i++) { dof_map[2*dof3 + (p - i) + (p + k*(p + 1))*(p + 1)] = o++; } // (3,0,4,7) -- left for (int k = 1; k < p; k++) // y - components for (int j = 0; j < p; j++) { dof_map[1*dof3 + 0 + ((p - 1 - j) + k*p)*(p + 1)] = -1 - (o++); } for (int k = 0; k < p; k++) // z - components for (int j = 1; j < p; j++) { dof_map[2*dof3 + 0 + ((p - j) + k*(p + 1))*(p + 1)] = o++; } // (4,5,6,7) -- top for (int j = 1; j < p; j++) // x - components for (int i = 0; i < p; i++) { dof_map[0*dof3 + i + (j + p*(p + 1))*p] = o++; } for (int j = 0; j < p; j++) // y - components for (int i = 1; i < p; i++) { dof_map[1*dof3 + i + (j + p*p)*(p + 1)] = o++; } // interior // x-components for (int k = 1; k < p; k++) for (int j = 1; j < p; j++) for (int i = 0; i < p; i++) { dof_map[0*dof3 + i + (j + k*(p + 1))*p] = o++; } // y-components for (int k = 1; k < p; k++) for (int j = 0; j < p; j++) for (int i = 1; i < p; i++) { dof_map[1*dof3 + i + (j + k*p)*(p + 1)] = o++; } // z-components for (int k = 0; k < p; k++) for (int j = 1; j < p; j++) for (int i = 1; i < p; i++) { dof_map[2*dof3 + i + (j + k*(p + 1))*(p + 1)] = o++; } // set dof2tk and Nodes o = 0; // x-components for (int k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i < p; i++) { int idx; if ((idx = dof_map[o++]) < 0) { dof2tk[idx = -1 - idx] = 3; } else { dof2tk[idx] = 0; } Nodes.IntPoint(idx).Set3(op[i], cp[j], cp[k]); } // y-components for (int k = 0; k <= p; k++) for (int j = 0; j < p; j++) for (int i = 0; i <= p; i++) { int idx; if ((idx = dof_map[o++]) < 0) { dof2tk[idx = -1 - idx] = 4; } else { dof2tk[idx] = 1; } Nodes.IntPoint(idx).Set3(cp[i], op[j], cp[k]); } // z-components for (int k = 0; k < p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { int idx; if ((idx = dof_map[o++]) < 0) { dof2tk[idx = -1 - idx] = 5; } else { dof2tk[idx] = 2; } Nodes.IntPoint(idx).Set3(cp[i], cp[j], op[k]); } } void ND_HexahedronElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p); Vector shape_cz(p + 1), shape_oz(p); #endif cbasis1d.Eval(ip.x, shape_cx); obasis1d.Eval(ip.x, shape_ox); cbasis1d.Eval(ip.y, shape_cy); obasis1d.Eval(ip.y, shape_oy); cbasis1d.Eval(ip.z, shape_cz); obasis1d.Eval(ip.z, shape_oz); int o = 0; // x-components for (int k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i < p; i++) { int idx, s; if ((idx = dof_map[o++]) < 0) { idx = -1 - idx, s = -1; } else { s = +1; } shape(idx,0) = s*shape_ox(i)*shape_cy(j)*shape_cz(k); shape(idx,1) = 0.; shape(idx,2) = 0.; } // y-components for (int k = 0; k <= p; k++) for (int j = 0; j < p; j++) for (int i = 0; i <= p; i++) { int idx, s; if ((idx = dof_map[o++]) < 0) { idx = -1 - idx, s = -1; } else { s = +1; } shape(idx,0) = 0.; shape(idx,1) = s*shape_cx(i)*shape_oy(j)*shape_cz(k); shape(idx,2) = 0.; } // z-components for (int k = 0; k < p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { int idx, s; if ((idx = dof_map[o++]) < 0) { idx = -1 - idx, s = -1; } else { s = +1; } shape(idx,0) = 0.; shape(idx,1) = 0.; shape(idx,2) = s*shape_cx(i)*shape_cy(j)*shape_oz(k); } } void ND_HexahedronElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p); Vector shape_cz(p + 1), shape_oz(p); Vector dshape_cx(p + 1), dshape_cy(p + 1), dshape_cz(p + 1); #endif cbasis1d.Eval(ip.x, shape_cx, dshape_cx); obasis1d.Eval(ip.x, shape_ox); cbasis1d.Eval(ip.y, shape_cy, dshape_cy); obasis1d.Eval(ip.y, shape_oy); cbasis1d.Eval(ip.z, shape_cz, dshape_cz); obasis1d.Eval(ip.z, shape_oz); int o = 0; // x-components for (int k = 0; k <= p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i < p; i++) { int idx, s; if ((idx = dof_map[o++]) < 0) { idx = -1 - idx, s = -1; } else { s = +1; } curl_shape(idx,0) = 0.; curl_shape(idx,1) = s*shape_ox(i)* shape_cy(j)*dshape_cz(k); curl_shape(idx,2) = -s*shape_ox(i)*dshape_cy(j)* shape_cz(k); } // y-components for (int k = 0; k <= p; k++) for (int j = 0; j < p; j++) for (int i = 0; i <= p; i++) { int idx, s; if ((idx = dof_map[o++]) < 0) { idx = -1 - idx, s = -1; } else { s = +1; } curl_shape(idx,0) = -s* shape_cx(i)*shape_oy(j)*dshape_cz(k); curl_shape(idx,1) = 0.; curl_shape(idx,2) = s*dshape_cx(i)*shape_oy(j)* shape_cz(k); } // z-components for (int k = 0; k < p; k++) for (int j = 0; j <= p; j++) for (int i = 0; i <= p; i++) { int idx, s; if ((idx = dof_map[o++]) < 0) { idx = -1 - idx, s = -1; } else { s = +1; } curl_shape(idx,0) = s* shape_cx(i)*dshape_cy(j)*shape_oz(k); curl_shape(idx,1) = -s*dshape_cx(i)* shape_cy(j)*shape_oz(k); curl_shape(idx,2) = 0.; } } const DofToQuad &VectorTensorFiniteElement::GetDofToQuad( const IntegrationRule &ir, DofToQuad::Mode mode) const { MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested"); return GetTensorDofToQuad(ir, mode, true); } const DofToQuad &VectorTensorFiniteElement::GetDofToQuadOpen( const IntegrationRule &ir, DofToQuad::Mode mode) const { MFEM_VERIFY(mode != DofToQuad::FULL, "invalid mode requested"); return GetTensorDofToQuad(ir, mode, false); } const DofToQuad &VectorTensorFiniteElement::GetTensorDofToQuad( const IntegrationRule &ir, DofToQuad::Mode mode, const bool closed) const { MFEM_VERIFY(mode == DofToQuad::TENSOR, "invalid mode requested"); for (int i = 0; i < (closed ? dof2quad_array.Size() : dof2quad_array_open.Size()); i++) { const DofToQuad &d2q = closed ? *dof2quad_array[i] : *dof2quad_array_open[i]; if (d2q.IntRule == &ir && d2q.mode == mode) { return d2q; } } DofToQuad *d2q = new DofToQuad; const int ndof = closed ? order + 1 : order; const int nqpt = (int)floor(pow(ir.GetNPoints(), 1.0/dim) + 0.5); d2q->FE = this; d2q->IntRule = &ir; d2q->mode = mode; d2q->ndof = ndof; d2q->nqpt = nqpt; d2q->B.SetSize(nqpt*ndof); d2q->Bt.SetSize(ndof*nqpt); d2q->G.SetSize(nqpt*ndof); d2q->Gt.SetSize(ndof*nqpt); Vector val(ndof), grad(ndof); for (int i = 0; i < nqpt; i++) { // The first 'nqpt' points in 'ir' have the same x-coordinates as those // of the 1D rule. if (closed) { cbasis1d.Eval(ir.IntPoint(i).x, val, grad); } else { obasis1d.Eval(ir.IntPoint(i).x, val, grad); } for (int j = 0; j < ndof; j++) { d2q->B[i+nqpt*j] = d2q->Bt[j+ndof*i] = val(j); d2q->G[i+nqpt*j] = d2q->Gt[j+ndof*i] = grad(j); } } if (closed) { dof2quad_array.Append(d2q); } else { dof2quad_array_open.Append(d2q); } return *d2q; } VectorTensorFiniteElement::~VectorTensorFiniteElement() { for (int i = 0; i < dof2quad_array_open.Size(); i++) { delete dof2quad_array_open[i]; } } const double ND_QuadrilateralElement::tk[8] = { 1.,0., 0.,1., -1.,0., 0.,-1. }; ND_QuadrilateralElement::ND_QuadrilateralElement(const int p, const int cb_type, const int ob_type) : VectorTensorFiniteElement(2, 2*p*(p + 1), p, cb_type, ob_type, H_CURL, DofMapType::L2_DOF_MAP), dof2tk(dof) { dof_map.SetSize(dof); const double *cp = poly1d.ClosedPoints(p, cb_type); const double *op = poly1d.OpenPoints(p - 1, ob_type); const int dof2 = dof/2; #ifndef MFEM_THREAD_SAFE shape_cx.SetSize(p + 1); shape_ox.SetSize(p); shape_cy.SetSize(p + 1); shape_oy.SetSize(p); dshape_cx.SetSize(p + 1); dshape_cy.SetSize(p + 1); #endif // edges int o = 0; for (int i = 0; i < p; i++) // (0,1) { dof_map[0*dof2 + i + 0*p] = o++; } for (int j = 0; j < p; j++) // (1,2) { dof_map[1*dof2 + p + j*(p + 1)] = o++; } for (int i = 0; i < p; i++) // (2,3) { dof_map[0*dof2 + (p - 1 - i) + p*p] = -1 - (o++); } for (int j = 0; j < p; j++) // (3,0) { dof_map[1*dof2 + 0 + (p - 1 - j)*(p + 1)] = -1 - (o++); } // interior // x-components for (int j = 1; j < p; j++) for (int i = 0; i < p; i++) { dof_map[0*dof2 + i + j*p] = o++; } // y-components for (int j = 0; j < p; j++) for (int i = 1; i < p; i++) { dof_map[1*dof2 + i + j*(p + 1)] = o++; } // set dof2tk and Nodes o = 0; // x-components for (int j = 0; j <= p; j++) for (int i = 0; i < p; i++) { int idx; if ((idx = dof_map[o++]) < 0) { dof2tk[idx = -1 - idx] = 2; } else { dof2tk[idx] = 0; } Nodes.IntPoint(idx).Set2(op[i], cp[j]); } // y-components for (int j = 0; j < p; j++) for (int i = 0; i <= p; i++) { int idx; if ((idx = dof_map[o++]) < 0) { dof2tk[idx = -1 - idx] = 3; } else { dof2tk[idx] = 1; } Nodes.IntPoint(idx).Set2(cp[i], op[j]); } } void ND_QuadrilateralElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p); #endif cbasis1d.Eval(ip.x, shape_cx); obasis1d.Eval(ip.x, shape_ox); cbasis1d.Eval(ip.y, shape_cy); obasis1d.Eval(ip.y, shape_oy); int o = 0; // x-components for (int j = 0; j <= p; j++) for (int i = 0; i < p; i++) { int idx, s; if ((idx = dof_map[o++]) < 0) { idx = -1 - idx, s = -1; } else { s = +1; } shape(idx,0) = s*shape_ox(i)*shape_cy(j); shape(idx,1) = 0.; } // y-components for (int j = 0; j < p; j++) for (int i = 0; i <= p; i++) { int idx, s; if ((idx = dof_map[o++]) < 0) { idx = -1 - idx, s = -1; } else { s = +1; } shape(idx,0) = 0.; shape(idx,1) = s*shape_cx(i)*shape_oy(j); } } void ND_QuadrilateralElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { const int p = order; #ifdef MFEM_THREAD_SAFE Vector shape_cx(p + 1), shape_ox(p), shape_cy(p + 1), shape_oy(p); Vector dshape_cx(p + 1), dshape_cy(p + 1); #endif cbasis1d.Eval(ip.x, shape_cx, dshape_cx); obasis1d.Eval(ip.x, shape_ox); cbasis1d.Eval(ip.y, shape_cy, dshape_cy); obasis1d.Eval(ip.y, shape_oy); int o = 0; // x-components for (int j = 0; j <= p; j++) for (int i = 0; i < p; i++) { int idx, s; if ((idx = dof_map[o++]) < 0) { idx = -1 - idx, s = -1; } else { s = +1; } curl_shape(idx,0) = -s*shape_ox(i)*dshape_cy(j); } // y-components for (int j = 0; j < p; j++) for (int i = 0; i <= p; i++) { int idx, s; if ((idx = dof_map[o++]) < 0) { idx = -1 - idx, s = -1; } else { s = +1; } curl_shape(idx,0) = s*dshape_cx(i)*shape_oy(j); } } const double ND_TetrahedronElement::tk[18] = { 1.,0.,0., 0.,1.,0., 0.,0.,1., -1.,1.,0., -1.,0.,1., 0.,-1.,1. }; const double ND_TetrahedronElement::c = 1./4.; ND_TetrahedronElement::ND_TetrahedronElement(const int p) : VectorFiniteElement(3, Geometry::TETRAHEDRON, p*(p + 2)*(p + 3)/2, p, H_CURL, FunctionSpace::Pk), dof2tk(dof) { const double *eop = poly1d.OpenPoints(p - 1); const double *fop = (p > 1) ? poly1d.OpenPoints(p - 2) : NULL; const double *iop = (p > 2) ? poly1d.OpenPoints(p - 3) : NULL; const int pm1 = p - 1, pm2 = p - 2, pm3 = p - 3; #ifndef MFEM_THREAD_SAFE shape_x.SetSize(p); shape_y.SetSize(p); shape_z.SetSize(p); shape_l.SetSize(p); dshape_x.SetSize(p); dshape_y.SetSize(p); dshape_z.SetSize(p); dshape_l.SetSize(p); u.SetSize(dof, dim); #else Vector shape_x(p), shape_y(p), shape_z(p), shape_l(p); #endif int o = 0; // edges for (int i = 0; i < p; i++) // (0,1) { Nodes.IntPoint(o).Set3(eop[i], 0., 0.); dof2tk[o++] = 0; } for (int i = 0; i < p; i++) // (0,2) { Nodes.IntPoint(o).Set3(0., eop[i], 0.); dof2tk[o++] = 1; } for (int i = 0; i < p; i++) // (0,3) { Nodes.IntPoint(o).Set3(0., 0., eop[i]); dof2tk[o++] = 2; } for (int i = 0; i < p; i++) // (1,2) { Nodes.IntPoint(o).Set3(eop[pm1-i], eop[i], 0.); dof2tk[o++] = 3; } for (int i = 0; i < p; i++) // (1,3) { Nodes.IntPoint(o).Set3(eop[pm1-i], 0., eop[i]); dof2tk[o++] = 4; } for (int i = 0; i < p; i++) // (2,3) { Nodes.IntPoint(o).Set3(0., eop[pm1-i], eop[i]); dof2tk[o++] = 5; } // faces for (int j = 0; j <= pm2; j++) // (1,2,3) for (int i = 0; i + j <= pm2; i++) { double w = fop[i] + fop[j] + fop[pm2-i-j]; Nodes.IntPoint(o).Set3(fop[pm2-i-j]/w, fop[i]/w, fop[j]/w); dof2tk[o++] = 3; Nodes.IntPoint(o).Set3(fop[pm2-i-j]/w, fop[i]/w, fop[j]/w); dof2tk[o++] = 4; } for (int j = 0; j <= pm2; j++) // (0,3,2) for (int i = 0; i + j <= pm2; i++) { double w = fop[i] + fop[j] + fop[pm2-i-j]; Nodes.IntPoint(o).Set3(0., fop[j]/w, fop[i]/w); dof2tk[o++] = 2; Nodes.IntPoint(o).Set3(0., fop[j]/w, fop[i]/w); dof2tk[o++] = 1; } for (int j = 0; j <= pm2; j++) // (0,1,3) for (int i = 0; i + j <= pm2; i++) { double w = fop[i] + fop[j] + fop[pm2-i-j]; Nodes.IntPoint(o).Set3(fop[i]/w, 0., fop[j]/w); dof2tk[o++] = 0; Nodes.IntPoint(o).Set3(fop[i]/w, 0., fop[j]/w); dof2tk[o++] = 2; } for (int j = 0; j <= pm2; j++) // (0,2,1) for (int i = 0; i + j <= pm2; i++) { double w = fop[i] + fop[j] + fop[pm2-i-j]; Nodes.IntPoint(o).Set3(fop[j]/w, fop[i]/w, 0.); dof2tk[o++] = 1; Nodes.IntPoint(o).Set3(fop[j]/w, fop[i]/w, 0.); dof2tk[o++] = 0; } // interior for (int k = 0; k <= pm3; k++) for (int j = 0; j + k <= pm3; j++) for (int i = 0; i + j + k <= pm3; i++) { double w = iop[i] + iop[j] + iop[k] + iop[pm3-i-j-k]; Nodes.IntPoint(o).Set3(iop[i]/w, iop[j]/w, iop[k]/w); dof2tk[o++] = 0; Nodes.IntPoint(o).Set3(iop[i]/w, iop[j]/w, iop[k]/w); dof2tk[o++] = 1; Nodes.IntPoint(o).Set3(iop[i]/w, iop[j]/w, iop[k]/w); dof2tk[o++] = 2; } DenseMatrix T(dof); for (int m = 0; m < dof; m++) { const IntegrationPoint &ip = Nodes.IntPoint(m); const double *tm = tk + 3*dof2tk[m]; o = 0; poly1d.CalcBasis(pm1, ip.x, shape_x); poly1d.CalcBasis(pm1, ip.y, shape_y); poly1d.CalcBasis(pm1, ip.z, shape_z); poly1d.CalcBasis(pm1, 1. - ip.x - ip.y - ip.z, shape_l); for (int k = 0; k <= pm1; k++) for (int j = 0; j + k <= pm1; j++) for (int i = 0; i + j + k <= pm1; i++) { double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_l(pm1-i-j-k); T(o++, m) = s * tm[0]; T(o++, m) = s * tm[1]; T(o++, m) = s * tm[2]; } for (int k = 0; k <= pm1; k++) for (int j = 0; j + k <= pm1; j++) { double s = shape_x(pm1-j-k)*shape_y(j)*shape_z(k); T(o++, m) = s*((ip.y - c)*tm[0] - (ip.x - c)*tm[1]); T(o++, m) = s*((ip.z - c)*tm[0] - (ip.x - c)*tm[2]); } for (int k = 0; k <= pm1; k++) { T(o++, m) = shape_y(pm1-k)*shape_z(k)*((ip.z - c)*tm[1] - (ip.y - c)*tm[2]); } } Ti.Factor(T); // mfem::out << "ND_TetrahedronElement(" << p << ") : "; Ti.TestInversion(); } void ND_TetrahedronElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { const int pm1 = order - 1; #ifdef MFEM_THREAD_SAFE const int p = order; Vector shape_x(p), shape_y(p), shape_z(p), shape_l(p); DenseMatrix u(dof, dim); #endif poly1d.CalcBasis(pm1, ip.x, shape_x); poly1d.CalcBasis(pm1, ip.y, shape_y); poly1d.CalcBasis(pm1, ip.z, shape_z); poly1d.CalcBasis(pm1, 1. - ip.x - ip.y - ip.z, shape_l); int n = 0; for (int k = 0; k <= pm1; k++) for (int j = 0; j + k <= pm1; j++) for (int i = 0; i + j + k <= pm1; i++) { double s = shape_x(i)*shape_y(j)*shape_z(k)*shape_l(pm1-i-j-k); u(n,0) = s; u(n,1) = 0.; u(n,2) = 0.; n++; u(n,0) = 0.; u(n,1) = s; u(n,2) = 0.; n++; u(n,0) = 0.; u(n,1) = 0.; u(n,2) = s; n++; } for (int k = 0; k <= pm1; k++) for (int j = 0; j + k <= pm1; j++) { double s = shape_x(pm1-j-k)*shape_y(j)*shape_z(k); u(n,0) = s*(ip.y - c); u(n,1) = -s*(ip.x - c); u(n,2) = 0.; n++; u(n,0) = s*(ip.z - c); u(n,1) = 0.; u(n,2) = -s*(ip.x - c); n++; } for (int k = 0; k <= pm1; k++) { double s = shape_y(pm1-k)*shape_z(k); u(n,0) = 0.; u(n,1) = s*(ip.z - c); u(n,2) = -s*(ip.y - c); n++; } Ti.Mult(u, shape); } void ND_TetrahedronElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { const int pm1 = order - 1; #ifdef MFEM_THREAD_SAFE const int p = order; Vector shape_x(p), shape_y(p), shape_z(p), shape_l(p); Vector dshape_x(p), dshape_y(p), dshape_z(p), dshape_l(p); DenseMatrix u(dof, dim); #endif poly1d.CalcBasis(pm1, ip.x, shape_x, dshape_x); poly1d.CalcBasis(pm1, ip.y, shape_y, dshape_y); poly1d.CalcBasis(pm1, ip.z, shape_z, dshape_z); poly1d.CalcBasis(pm1, 1. - ip.x - ip.y - ip.z, shape_l, dshape_l); int n = 0; for (int k = 0; k <= pm1; k++) for (int j = 0; j + k <= pm1; j++) for (int i = 0; i + j + k <= pm1; i++) { int l = pm1-i-j-k; const double dx = (dshape_x(i)*shape_l(l) - shape_x(i)*dshape_l(l))*shape_y(j)*shape_z(k); const double dy = (dshape_y(j)*shape_l(l) - shape_y(j)*dshape_l(l))*shape_x(i)*shape_z(k); const double dz = (dshape_z(k)*shape_l(l) - shape_z(k)*dshape_l(l))*shape_x(i)*shape_y(j); u(n,0) = 0.; u(n,1) = dz; u(n,2) = -dy; n++; u(n,0) = -dz; u(n,1) = 0.; u(n,2) = dx; n++; u(n,0) = dy; u(n,1) = -dx; u(n,2) = 0.; n++; } for (int k = 0; k <= pm1; k++) for (int j = 0; j + k <= pm1; j++) { int i = pm1 - j - k; // s = shape_x(i)*shape_y(j)*shape_z(k); // curl of s*(ip.y - c, -(ip.x - c), 0): u(n,0) = shape_x(i)*(ip.x - c)*shape_y(j)*dshape_z(k); u(n,1) = shape_x(i)*shape_y(j)*(ip.y - c)*dshape_z(k); u(n,2) = -((dshape_x(i)*(ip.x - c) + shape_x(i))*shape_y(j)*shape_z(k) + (dshape_y(j)*(ip.y - c) + shape_y(j))*shape_x(i)*shape_z(k)); n++; // curl of s*(ip.z - c, 0, -(ip.x - c)): u(n,0) = -shape_x(i)*(ip.x - c)*dshape_y(j)*shape_z(k); u(n,1) = (shape_x(i)*shape_y(j)*(dshape_z(k)*(ip.z - c) + shape_z(k)) + (dshape_x(i)*(ip.x - c) + shape_x(i))*shape_y(j)*shape_z(k)); u(n,2) = -shape_x(i)*dshape_y(j)*shape_z(k)*(ip.z - c); n++; } for (int k = 0; k <= pm1; k++) { int j = pm1 - k; // curl of shape_y(j)*shape_z(k)*(0, ip.z - c, -(ip.y - c)): u(n,0) = -((dshape_y(j)*(ip.y - c) + shape_y(j))*shape_z(k) + shape_y(j)*(dshape_z(k)*(ip.z - c) + shape_z(k))); u(n,1) = 0.; u(n,2) = 0.; n++; } Ti.Mult(u, curl_shape); } const double ND_TriangleElement::tk[8] = { 1.,0., -1.,1., 0.,-1., 0.,1. }; const double ND_TriangleElement::c = 1./3.; ND_TriangleElement::ND_TriangleElement(const int p) : VectorFiniteElement(2, Geometry::TRIANGLE, p*(p + 2), p, H_CURL, FunctionSpace::Pk), dof2tk(dof) { const double *eop = poly1d.OpenPoints(p - 1); const double *iop = (p > 1) ? poly1d.OpenPoints(p - 2) : NULL; const int pm1 = p - 1, pm2 = p - 2; #ifndef MFEM_THREAD_SAFE shape_x.SetSize(p); shape_y.SetSize(p); shape_l.SetSize(p); dshape_x.SetSize(p); dshape_y.SetSize(p); dshape_l.SetSize(p); u.SetSize(dof, dim); curlu.SetSize(dof); #else Vector shape_x(p), shape_y(p), shape_l(p); #endif int n = 0; // edges for (int i = 0; i < p; i++) // (0,1) { Nodes.IntPoint(n).Set2(eop[i], 0.); dof2tk[n++] = 0; } for (int i = 0; i < p; i++) // (1,2) { Nodes.IntPoint(n).Set2(eop[pm1-i], eop[i]); dof2tk[n++] = 1; } for (int i = 0; i < p; i++) // (2,0) { Nodes.IntPoint(n).Set2(0., eop[pm1-i]); dof2tk[n++] = 2; } // interior for (int j = 0; j <= pm2; j++) for (int i = 0; i + j <= pm2; i++) { double w = iop[i] + iop[j] + iop[pm2-i-j]; Nodes.IntPoint(n).Set2(iop[i]/w, iop[j]/w); dof2tk[n++] = 0; Nodes.IntPoint(n).Set2(iop[i]/w, iop[j]/w); dof2tk[n++] = 3; } DenseMatrix T(dof); for (int m = 0; m < dof; m++) { const IntegrationPoint &ip = Nodes.IntPoint(m); const double *tm = tk + 2*dof2tk[m]; n = 0; poly1d.CalcBasis(pm1, ip.x, shape_x); poly1d.CalcBasis(pm1, ip.y, shape_y); poly1d.CalcBasis(pm1, 1. - ip.x - ip.y, shape_l); for (int j = 0; j <= pm1; j++) for (int i = 0; i + j <= pm1; i++) { double s = shape_x(i)*shape_y(j)*shape_l(pm1-i-j); T(n++, m) = s * tm[0]; T(n++, m) = s * tm[1]; } for (int j = 0; j <= pm1; j++) { T(n++, m) = shape_x(pm1-j)*shape_y(j)*((ip.y - c)*tm[0] - (ip.x - c)*tm[1]); } } Ti.Factor(T); // mfem::out << "ND_TriangleElement(" << p << ") : "; Ti.TestInversion(); } void ND_TriangleElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { const int pm1 = order - 1; #ifdef MFEM_THREAD_SAFE const int p = order; Vector shape_x(p), shape_y(p), shape_l(p); DenseMatrix u(dof, dim); #endif poly1d.CalcBasis(pm1, ip.x, shape_x); poly1d.CalcBasis(pm1, ip.y, shape_y); poly1d.CalcBasis(pm1, 1. - ip.x - ip.y, shape_l); int n = 0; for (int j = 0; j <= pm1; j++) for (int i = 0; i + j <= pm1; i++) { double s = shape_x(i)*shape_y(j)*shape_l(pm1-i-j); u(n,0) = s; u(n,1) = 0; n++; u(n,0) = 0; u(n,1) = s; n++; } for (int j = 0; j <= pm1; j++) { double s = shape_x(pm1-j)*shape_y(j); u(n,0) = s*(ip.y - c); u(n,1) = -s*(ip.x - c); n++; } Ti.Mult(u, shape); } void ND_TriangleElement::CalcCurlShape(const IntegrationPoint &ip, DenseMatrix &curl_shape) const { const int pm1 = order - 1; #ifdef MFEM_THREAD_SAFE const int p = order; Vector shape_x(p), shape_y(p), shape_l(p); Vector dshape_x(p), dshape_y(p), dshape_l(p); Vector curlu(dof); #endif poly1d.CalcBasis(pm1, ip.x, shape_x, dshape_x); poly1d.CalcBasis(pm1, ip.y, shape_y, dshape_y); poly1d.CalcBasis(pm1, 1. - ip.x - ip.y, shape_l, dshape_l); int n = 0; for (int j = 0; j <= pm1; j++) for (int i = 0; i + j <= pm1; i++) { int l = pm1-i-j; const double dx = (dshape_x(i)*shape_l(l) - shape_x(i)*dshape_l(l)) * shape_y(j); const double dy = (dshape_y(j)*shape_l(l) - shape_y(j)*dshape_l(l)) * shape_x(i); curlu(n++) = -dy; curlu(n++) = dx; } for (int j = 0; j <= pm1; j++) { int i = pm1 - j; // curl of shape_x(i)*shape_y(j) * (ip.y - c, -(ip.x - c), 0): curlu(n++) = -((dshape_x(i)*(ip.x - c) + shape_x(i)) * shape_y(j) + (dshape_y(j)*(ip.y - c) + shape_y(j)) * shape_x(i)); } Vector curl2d(curl_shape.Data(),dof); Ti.Mult(curlu, curl2d); } const double ND_SegmentElement::tk[1] = { 1. }; ND_SegmentElement::ND_SegmentElement(const int p, const int ob_type) : VectorFiniteElement(1, Geometry::SEGMENT, p, p - 1, H_CURL, FunctionSpace::Pk), obasis1d(poly1d.GetBasis(p - 1, VerifyOpen(ob_type))), dof2tk(dof) { const double *op = poly1d.OpenPoints(p - 1, ob_type); // set dof2tk and Nodes for (int i = 0; i < p; i++) { dof2tk[i] = 0; Nodes.IntPoint(i).x = op[i]; } } void ND_SegmentElement::CalcVShape(const IntegrationPoint &ip, DenseMatrix &shape) const { Vector vshape(shape.Data(), dof); obasis1d.Eval(ip.x, vshape); } void NURBS1DFiniteElement::SetOrder() const { order = kv[0]->GetOrder(); dof = order + 1; weights.SetSize(dof); shape_x.SetSize(dof); } void NURBS1DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { kv[0]->CalcShape(shape, ijk[0], ip.x); double sum = 0.0; for (int i = 0; i <= order; i++) { sum += (shape(i) *= weights(i)); } shape /= sum; } void NURBS1DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { Vector grad(dshape.Data(), dof); kv[0]->CalcShape (shape_x, ijk[0], ip.x); kv[0]->CalcDShape(grad, ijk[0], ip.x); double sum = 0.0, dsum = 0.0; for (int i = 0; i <= order; i++) { sum += (shape_x(i) *= weights(i)); dsum += ( grad(i) *= weights(i)); } sum = 1.0/sum; add(sum, grad, -dsum*sum*sum, shape_x, grad); } void NURBS1DFiniteElement::CalcHessian (const IntegrationPoint &ip, DenseMatrix &hessian) const { Vector grad(dof); Vector hess(hessian.Data(), dof); kv[0]->CalcShape (shape_x, ijk[0], ip.x); kv[0]->CalcDShape(grad, ijk[0], ip.x); kv[0]->CalcD2Shape(hess, ijk[0], ip.x); double sum = 0.0, dsum = 0.0, d2sum = 0.0; for (int i = 0; i <= order; i++) { sum += (shape_x(i) *= weights(i)); dsum += ( grad(i) *= weights(i)); d2sum += ( hess(i) *= weights(i)); } sum = 1.0/sum; add(sum, hess, -2*dsum*sum*sum, grad, hess); add(1.0, hess, (-d2sum + 2*dsum*dsum*sum)*sum*sum, shape_x, hess); } void NURBS2DFiniteElement::SetOrder() const { orders[0] = kv[0]->GetOrder(); orders[1] = kv[1]->GetOrder(); shape_x.SetSize(orders[0]+1); shape_y.SetSize(orders[1]+1); dshape_x.SetSize(orders[0]+1); dshape_y.SetSize(orders[1]+1); d2shape_x.SetSize(orders[0]+1); d2shape_y.SetSize(orders[1]+1); order = max(orders[0], orders[1]); dof = (orders[0] + 1)*(orders[1] + 1); u.SetSize(dof); du.SetSize(dof); weights.SetSize(dof); } void NURBS2DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { kv[0]->CalcShape(shape_x, ijk[0], ip.x); kv[1]->CalcShape(shape_y, ijk[1], ip.y); double sum = 0.0; for (int o = 0, j = 0; j <= orders[1]; j++) { const double sy = shape_y(j); for (int i = 0; i <= orders[0]; i++, o++) { sum += ( shape(o) = shape_x(i)*sy*weights(o) ); } } shape /= sum; } void NURBS2DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double sum, dsum[2]; kv[0]->CalcShape ( shape_x, ijk[0], ip.x); kv[1]->CalcShape ( shape_y, ijk[1], ip.y); kv[0]->CalcDShape(dshape_x, ijk[0], ip.x); kv[1]->CalcDShape(dshape_y, ijk[1], ip.y); sum = dsum[0] = dsum[1] = 0.0; for (int o = 0, j = 0; j <= orders[1]; j++) { const double sy = shape_y(j), dsy = dshape_y(j); for (int i = 0; i <= orders[0]; i++, o++) { sum += ( u(o) = shape_x(i)*sy*weights(o) ); dsum[0] += ( dshape(o,0) = dshape_x(i)*sy *weights(o) ); dsum[1] += ( dshape(o,1) = shape_x(i)*dsy*weights(o) ); } } sum = 1.0/sum; dsum[0] *= sum*sum; dsum[1] *= sum*sum; for (int o = 0; o < dof; o++) { dshape(o,0) = dshape(o,0)*sum - u(o)*dsum[0]; dshape(o,1) = dshape(o,1)*sum - u(o)*dsum[1]; } } void NURBS2DFiniteElement::CalcHessian (const IntegrationPoint &ip, DenseMatrix &hessian) const { double sum, dsum[2], d2sum[3]; kv[0]->CalcShape ( shape_x, ijk[0], ip.x); kv[1]->CalcShape ( shape_y, ijk[1], ip.y); kv[0]->CalcDShape(dshape_x, ijk[0], ip.x); kv[1]->CalcDShape(dshape_y, ijk[1], ip.y); kv[0]->CalcD2Shape(d2shape_x, ijk[0], ip.x); kv[1]->CalcD2Shape(d2shape_y, ijk[1], ip.y); sum = dsum[0] = dsum[1] = 0.0; d2sum[0] = d2sum[1] = d2sum[2] = 0.0; for (int o = 0, j = 0; j <= orders[1]; j++) { const double sy = shape_y(j), dsy = dshape_y(j), d2sy = d2shape_y(j); for (int i = 0; i <= orders[0]; i++, o++) { const double sx = shape_x(i), dsx = dshape_x(i), d2sx = d2shape_x(i); sum += ( u(o) = sx*sy*weights(o) ); dsum[0] += ( du(o,0) = dsx*sy*weights(o) ); dsum[1] += ( du(o,1) = sx*dsy*weights(o) ); d2sum[0] += ( hessian(o,0) = d2sx*sy*weights(o) ); d2sum[1] += ( hessian(o,1) = dsx*dsy*weights(o) ); d2sum[2] += ( hessian(o,2) = sx*d2sy*weights(o) ); } } sum = 1.0/sum; dsum[0] *= sum; dsum[1] *= sum; d2sum[0] *= sum; d2sum[1] *= sum; d2sum[2] *= sum; for (int o = 0; o < dof; o++) { hessian(o,0) = hessian(o,0)*sum - 2*du(o,0)*sum*dsum[0] + u[o]*sum*(2*dsum[0]*dsum[0] - d2sum[0]); hessian(o,1) = hessian(o,1)*sum - du(o,0)*sum*dsum[1] - du(o,1)*sum*dsum[0] + u[o]*sum*(2*dsum[0]*dsum[1] - d2sum[1]); hessian(o,2) = hessian(o,2)*sum - 2*du(o,1)*sum*dsum[1] + u[o]*sum*(2*dsum[1]*dsum[1] - d2sum[2]); } } void NURBS3DFiniteElement::SetOrder() const { orders[0] = kv[0]->GetOrder(); orders[1] = kv[1]->GetOrder(); orders[2] = kv[2]->GetOrder(); shape_x.SetSize(orders[0]+1); shape_y.SetSize(orders[1]+1); shape_z.SetSize(orders[2]+1); dshape_x.SetSize(orders[0]+1); dshape_y.SetSize(orders[1]+1); dshape_z.SetSize(orders[2]+1); d2shape_x.SetSize(orders[0]+1); d2shape_y.SetSize(orders[1]+1); d2shape_z.SetSize(orders[2]+1); order = max(max(orders[0], orders[1]), orders[2]); dof = (orders[0] + 1)*(orders[1] + 1)*(orders[2] + 1); u.SetSize(dof); du.SetSize(dof); weights.SetSize(dof); } void NURBS3DFiniteElement::CalcShape(const IntegrationPoint &ip, Vector &shape) const { kv[0]->CalcShape(shape_x, ijk[0], ip.x); kv[1]->CalcShape(shape_y, ijk[1], ip.y); kv[2]->CalcShape(shape_z, ijk[2], ip.z); double sum = 0.0; for (int o = 0, k = 0; k <= orders[2]; k++) { const double sz = shape_z(k); for (int j = 0; j <= orders[1]; j++) { const double sy_sz = shape_y(j)*sz; for (int i = 0; i <= orders[0]; i++, o++) { sum += ( shape(o) = shape_x(i)*sy_sz*weights(o) ); } } } shape /= sum; } void NURBS3DFiniteElement::CalcDShape(const IntegrationPoint &ip, DenseMatrix &dshape) const { double sum, dsum[3]; kv[0]->CalcShape ( shape_x, ijk[0], ip.x); kv[1]->CalcShape ( shape_y, ijk[1], ip.y); kv[2]->CalcShape ( shape_z, ijk[2], ip.z); kv[0]->CalcDShape(dshape_x, ijk[0], ip.x); kv[1]->CalcDShape(dshape_y, ijk[1], ip.y); kv[2]->CalcDShape(dshape_z, ijk[2], ip.z); sum = dsum[0] = dsum[1] = dsum[2] = 0.0; for (int o = 0, k = 0; k <= orders[2]; k++) { const double sz = shape_z(k), dsz = dshape_z(k); for (int j = 0; j <= orders[1]; j++) { const double sy_sz = shape_y(j)* sz; const double dsy_sz = dshape_y(j)* sz; const double sy_dsz = shape_y(j)*dsz; for (int i = 0; i <= orders[0]; i++, o++) { sum += ( u(o) = shape_x(i)*sy_sz*weights(o) ); dsum[0] += ( dshape(o,0) = dshape_x(i)* sy_sz *weights(o) ); dsum[1] += ( dshape(o,1) = shape_x(i)*dsy_sz *weights(o) ); dsum[2] += ( dshape(o,2) = shape_x(i)* sy_dsz*weights(o) ); } } } sum = 1.0/sum; dsum[0] *= sum*sum; dsum[1] *= sum*sum; dsum[2] *= sum*sum; for (int o = 0; o < dof; o++) { dshape(o,0) = dshape(o,0)*sum - u(o)*dsum[0]; dshape(o,1) = dshape(o,1)*sum - u(o)*dsum[1]; dshape(o,2) = dshape(o,2)*sum - u(o)*dsum[2]; } } void NURBS3DFiniteElement::CalcHessian (const IntegrationPoint &ip, DenseMatrix &hessian) const { double sum, dsum[3], d2sum[6]; kv[0]->CalcShape ( shape_x, ijk[0], ip.x); kv[1]->CalcShape ( shape_y, ijk[1], ip.y); kv[2]->CalcShape ( shape_z, ijk[2], ip.z); kv[0]->CalcDShape(dshape_x, ijk[0], ip.x); kv[1]->CalcDShape(dshape_y, ijk[1], ip.y); kv[2]->CalcDShape(dshape_z, ijk[2], ip.z); kv[0]->CalcD2Shape(d2shape_x, ijk[0], ip.x); kv[1]->CalcD2Shape(d2shape_y, ijk[1], ip.y); kv[2]->CalcD2Shape(d2shape_z, ijk[2], ip.z); sum = dsum[0] = dsum[1] = dsum[2] = 0.0; d2sum[0] = d2sum[1] = d2sum[2] = d2sum[3] = d2sum[4] = d2sum[5] = 0.0; for (int o = 0, k = 0; k <= orders[2]; k++) { const double sz = shape_z(k), dsz = dshape_z(k), d2sz = d2shape_z(k); for (int j = 0; j <= orders[1]; j++) { const double sy = shape_y(j), dsy = dshape_y(j), d2sy = d2shape_y(j); for (int i = 0; i <= orders[0]; i++, o++) { const double sx = shape_x(i), dsx = dshape_x(i), d2sx = d2shape_x(i); sum += ( u(o) = sx*sy*sz*weights(o) ); dsum[0] += ( du(o,0) = dsx*sy*sz*weights(o) ); dsum[1] += ( du(o,1) = sx*dsy*sz*weights(o) ); dsum[2] += ( du(o,2) = sx*sy*dsz*weights(o) ); d2sum[0] += ( hessian(o,0) = d2sx*sy*sz*weights(o) ); d2sum[1] += ( hessian(o,1) = dsx*dsy*sz*weights(o) ); d2sum[2] += ( hessian(o,2) = dsx*sy*dsz*weights(o) ); d2sum[3] += ( hessian(o,3) = sx*dsy*dsz*weights(o) ); d2sum[4] += ( hessian(o,4) = sx*sy*d2sz*weights(o) ); d2sum[5] += ( hessian(o,5) = sx*d2sy*sz*weights(o) ); } } } sum = 1.0/sum; dsum[0] *= sum; dsum[1] *= sum; dsum[2] *= sum; d2sum[0] *= sum; d2sum[1] *= sum; d2sum[2] *= sum; d2sum[3] *= sum; d2sum[4] *= sum; d2sum[5] *= sum; for (int o = 0; o < dof; o++) { hessian(o,0) = hessian(o,0)*sum - 2*du(o,0)*sum*dsum[0] + u[o]*sum*(2*dsum[0]*dsum[0] - d2sum[0]); hessian(o,1) = hessian(o,1)*sum - du(o,0)*sum*dsum[1] - du(o,1)*sum*dsum[0] + u[o]*sum*(2*dsum[0]*dsum[1] - d2sum[1]); hessian(o,2) = hessian(o,2)*sum - du(o,0)*sum*dsum[2] - du(o,2)*sum*dsum[0] + u[o]*sum*(2*dsum[0]*dsum[2] - d2sum[2]); hessian(o,3) = hessian(o,3)*sum - du(o,1)*sum*dsum[2] - du(o,2)*sum*dsum[1] + u[o]*sum*(2*dsum[1]*dsum[2] - d2sum[3]); hessian(o,4) = hessian(o,4)*sum - 2*du(o,2)*sum*dsum[2] + u[o]*sum*(2*dsum[2]*dsum[2] - d2sum[4]); hessian(o,5) = hessian(o,5)*sum - 2*du(o,1)*sum*dsum[1] + u[o]*sum*(2*dsum[1]*dsum[1] - d2sum[5]); } } // Global object definitions // Object declared in mesh/triangle.hpp. // Defined here to ensure it is constructed before 'Geometries'. Linear2DFiniteElement TriangleFE; // Object declared in mesh/tetrahedron.hpp. // Defined here to ensure it is constructed before 'Geometries'. Linear3DFiniteElement TetrahedronFE; // Object declared in mesh/wedge.hpp. // Defined here to ensure it is constructed after 'poly1d' and before // 'Geometries'. // TODO: define as thread_local to prevent race conditions in GLVis, because // there is no "LinearWedgeFiniteElement" and WedgeFE is in turn used from two // different threads for different things in GLVis. We also don't want to turn // MFEM_THREAD_SAFE on globally. (See PR #731) H1_WedgeElement WedgeFE(1); // Object declared in geom.hpp. // Construct 'Geometries' after 'TriangleFE', 'TetrahedronFE', and 'WedgeFE'. Geometry Geometries; }