// 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. #include #include "fem.hpp" namespace mfem { void LinearFormIntegrator::AssembleRHSElementVect( const FiniteElement &el, FaceElementTransformations &Tr, Vector &elvect) { mfem_error("LinearFormIntegrator::AssembleRHSElementVect(...)"); } void DomainLFIntegrator::AssembleRHSElementVect(const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dof = el.GetDof(); shape.SetSize(dof); // vector of size dof elvect.SetSize(dof); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { // ir = &IntRules.Get(el.GetGeomType(), // oa * el.GetOrder() + ob + Tr.OrderW()); ir = &IntRules.Get(el.GetGeomType(), oa * el.GetOrder() + ob); } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); Tr.SetIntPoint (&ip); double val = Tr.Weight() * Q.Eval(Tr, ip); el.CalcShape(ip, shape); add(elvect, ip.weight * val, shape, elvect); } } void DomainLFIntegrator::AssembleDeltaElementVect( const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect) { MFEM_ASSERT(delta != NULL, "coefficient must be DeltaCoefficient"); elvect.SetSize(fe.GetDof()); fe.CalcPhysShape(Trans, elvect); elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint()); } void BoundaryLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dof = el.GetDof(); shape.SetSize(dof); // vector of size dof elvect.SetSize(dof); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { int intorder = oa * el.GetOrder() + ob; // <---------- ir = &IntRules.Get(el.GetGeomType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); Tr.SetIntPoint (&ip); double val = Tr.Weight() * Q.Eval(Tr, ip); el.CalcShape(ip, shape); add(elvect, ip.weight * val, shape, elvect); } } void BoundaryLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, FaceElementTransformations &Tr, Vector &elvect) { int dof = el.GetDof(); shape.SetSize(dof); // vector of size dof elvect.SetSize(dof); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { int intorder = oa * el.GetOrder() + ob; // <------ user control ir = &IntRules.Get(Tr.FaceGeom, intorder); // of integration order } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); IntegrationPoint eip; Tr.Loc1.Transform(ip, eip); Tr.Face->SetIntPoint (&ip); double val = Tr.Face->Weight() * ip.weight * Q.Eval(*Tr.Face, ip); el.CalcShape(eip, shape); add(elvect, val, shape, elvect); } } void BoundaryNormalLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dim = el.GetDim()+1; int dof = el.GetDof(); Vector nor(dim), Qvec; shape.SetSize(dof); elvect.SetSize(dof); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { int intorder = oa * el.GetOrder() + ob; // <---------- ir = &IntRules.Get(el.GetGeomType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); Tr.SetIntPoint(&ip); CalcOrtho(Tr.Jacobian(), nor); Q.Eval(Qvec, Tr, ip); el.CalcShape(ip, shape); elvect.Add(ip.weight*(Qvec*nor), shape); } } void BoundaryTangentialLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dim = el.GetDim()+1; int dof = el.GetDof(); Vector tangent(dim), Qvec; shape.SetSize(dof); elvect.SetSize(dof); elvect = 0.0; if (dim != 2) { mfem_error("These methods make sense only in 2D problems."); } const IntegrationRule *ir = IntRule; if (ir == NULL) { int intorder = oa * el.GetOrder() + ob; // <---------- ir = &IntRules.Get(el.GetGeomType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); Tr.SetIntPoint(&ip); const DenseMatrix &Jac = Tr.Jacobian(); tangent(0) = Jac(0,0); tangent(1) = Jac(1,0); Q.Eval(Qvec, Tr, ip); el.CalcShape(ip, shape); add(elvect, ip.weight*(Qvec*tangent), shape, elvect); } } void VectorDomainLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int vdim = Q.GetVDim(); int dof = el.GetDof(); double val,cf; shape.SetSize(dof); // vector of size dof elvect.SetSize(dof * vdim); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { int intorder = 2*el.GetOrder(); ir = &IntRules.Get(el.GetGeomType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); Tr.SetIntPoint (&ip); val = Tr.Weight(); el.CalcShape(ip, shape); Q.Eval (Qvec, Tr, ip); for (int k = 0; k < vdim; k++) { cf = val * Qvec(k); for (int s = 0; s < dof; s++) { elvect(dof*k+s) += ip.weight * cf * shape(s); } } } } void VectorDomainLFIntegrator::AssembleDeltaElementVect( const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect) { MFEM_ASSERT(vec_delta != NULL, "coefficient must be VectorDeltaCoefficient"); int vdim = Q.GetVDim(); int dof = fe.GetDof(); shape.SetSize(dof); fe.CalcPhysShape(Trans, shape); vec_delta->EvalDelta(Qvec, Trans, Trans.GetIntPoint()); elvect.SetSize(dof*vdim); DenseMatrix elvec_as_mat(elvect.GetData(), dof, vdim); MultVWt(shape, Qvec, elvec_as_mat); } void VectorBoundaryLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int vdim = Q.GetVDim(); int dof = el.GetDof(); shape.SetSize(dof); vec.SetSize(vdim); elvect.SetSize(dof * vdim); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { int intorder = 2*el.GetOrder(); ir = &IntRules.Get(el.GetGeomType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); Q.Eval(vec, Tr, ip); Tr.SetIntPoint (&ip); vec *= Tr.Weight() * ip.weight; el.CalcShape(ip, shape); for (int k = 0; k < vdim; k++) for (int s = 0; s < dof; s++) { elvect(dof*k+s) += vec(k) * shape(s); } } } void VectorBoundaryLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, FaceElementTransformations &Tr, Vector &elvect) { int vdim = Q.GetVDim(); int dof = el.GetDof(); shape.SetSize(dof); vec.SetSize(vdim); elvect.SetSize(dof * vdim); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { int intorder = 2*el.GetOrder(); ir = &IntRules.Get(Tr.GetGeometryType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); IntegrationPoint eip; Tr.Loc1.Transform(ip, eip); Tr.SetIntPoint(&ip); // Use Tr transformation in case Q depends on boundary attribute Q.Eval(vec, Tr, ip); vec *= Tr.Weight() * ip.weight; el.CalcShape(eip, shape); for (int k = 0; k < vdim; k++) { for (int s = 0; s < dof; s++) { elvect(dof*k+s) += vec(k) * shape(s); } } } } void VectorFEDomainLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dof = el.GetDof(); int spaceDim = Tr.GetSpaceDim(); vshape.SetSize(dof,spaceDim); vec.SetSize(spaceDim); elvect.SetSize(dof); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { // int intorder = 2*el.GetOrder() - 1; // ok for O(h^{k+1}) conv. in L2 int intorder = 2*el.GetOrder(); ir = &IntRules.Get(el.GetGeomType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); Tr.SetIntPoint (&ip); el.CalcVShape(Tr, vshape); QF.Eval (vec, Tr, ip); vec *= ip.weight * Tr.Weight(); vshape.AddMult (vec, elvect); } } void VectorFEDomainLFIntegrator::AssembleDeltaElementVect( const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect) { MFEM_ASSERT(vec_delta != NULL, "coefficient must be VectorDeltaCoefficient"); int dof = fe.GetDof(); int spaceDim = Trans.GetSpaceDim(); vshape.SetSize(dof, spaceDim); fe.CalcPhysVShape(Trans, vshape); vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint()); elvect.SetSize(dof); vshape.Mult(vec, elvect); } void VectorBoundaryFluxLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dim = el.GetDim()+1; int dof = el.GetDof(); shape.SetSize (dof); nor.SetSize (dim); elvect.SetSize (dim*dof); const IntegrationRule *ir = IntRule; if (ir == NULL) { ir = &IntRules.Get(el.GetGeomType(), el.GetOrder() + 1); } elvect = 0.0; for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); Tr.SetIntPoint (&ip); CalcOrtho(Tr.Jacobian(), nor); el.CalcShape (ip, shape); nor *= Sign * ip.weight * F -> Eval (Tr, ip); for (int j = 0; j < dof; j++) for (int k = 0; k < dim; k++) { elvect(dof*k+j) += nor(k) * shape(j); } } } void VectorFEBoundaryFluxLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dof = el.GetDof(); shape.SetSize(dof); elvect.SetSize(dof); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { int intorder = oa * el.GetOrder() + ob; // <---------- ir = &IntRules.Get(el.GetGeomType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); el.CalcShape(ip, shape); double val = ip.weight; if (F) { Tr.SetIntPoint (&ip); val *= F->Eval(Tr, ip); } elvect.Add(val, shape); } } void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { int dof = el.GetDof(); DenseMatrix vshape(dof, 2); Vector f_loc(3); Vector f_hat(2); elvect.SetSize(dof); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { int intorder = oa * el.GetOrder() + ob; // <---------- ir = &IntRules.Get(el.GetGeomType(), intorder); } for (int i = 0; i < ir->GetNPoints(); i++) { const IntegrationPoint &ip = ir->IntPoint(i); Tr.SetIntPoint(&ip); f.Eval(f_loc, Tr, ip); Tr.Jacobian().MultTranspose(f_loc, f_hat); el.CalcVShape(ip, vshape); Swap(f_hat(0), f_hat(1)); f_hat(0) = -f_hat(0); f_hat *= ip.weight; vshape.AddMult(f_hat, elvect); } } void BoundaryFlowIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { mfem_error("BoundaryFlowIntegrator::AssembleRHSElementVect\n" " is not implemented as boundary integrator!\n" " Use LinearForm::AddBdrFaceIntegrator instead of\n" " LinearForm::AddBoundaryIntegrator."); } void BoundaryFlowIntegrator::AssembleRHSElementVect( const FiniteElement &el, FaceElementTransformations &Tr, Vector &elvect) { int dim, ndof, order; double un, w, vu_data[3], nor_data[3]; dim = el.GetDim(); ndof = el.GetDof(); Vector vu(vu_data, dim), nor(nor_data, dim); const IntegrationRule *ir = IntRule; if (ir == NULL) { // Assuming order(u)==order(mesh) order = Tr.Elem1->OrderW() + 2*el.GetOrder(); if (el.Space() == FunctionSpace::Pk) { order++; } ir = &IntRules.Get(Tr.GetGeometryType(), order); } shape.SetSize(ndof); elvect.SetSize(ndof); elvect = 0.0; for (int p = 0; p < ir->GetNPoints(); p++) { const IntegrationPoint &ip = ir->IntPoint(p); IntegrationPoint eip; Tr.Loc1.Transform(ip, eip); el.CalcShape(eip, shape); Tr.SetIntPoint(&ip); // Use Tr.Elem1 transformation for u so that it matches the coefficient // used with the ConvectionIntegrator and/or the DGTraceIntegrator. u->Eval(vu, *Tr.Elem1, eip); if (dim == 1) { nor(0) = 2*eip.x - 1.0; } else { CalcOrtho(Tr.Jacobian(), nor); } un = vu * nor; w = 0.5*alpha*un - beta*fabs(un); w *= ip.weight*f->Eval(Tr, ip); elvect.Add(w, shape); } } void DGDirichletLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { mfem_error("DGDirichletLFIntegrator::AssembleRHSElementVect"); } void DGDirichletLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, FaceElementTransformations &Tr, Vector &elvect) { int dim, ndof; bool kappa_is_nonzero = (kappa != 0.); double w; dim = el.GetDim(); ndof = el.GetDof(); nor.SetSize(dim); nh.SetSize(dim); ni.SetSize(dim); adjJ.SetSize(dim); if (MQ) { mq.SetSize(dim); } shape.SetSize(ndof); dshape.SetSize(ndof, dim); dshape_dn.SetSize(ndof); elvect.SetSize(ndof); elvect = 0.0; const IntegrationRule *ir = IntRule; if (ir == NULL) { // a simple choice for the integration order; is this OK? int order = 2*el.GetOrder(); ir = &IntRules.Get(Tr.GetGeometryType(), order); } for (int p = 0; p < ir->GetNPoints(); p++) { const IntegrationPoint &ip = ir->IntPoint(p); IntegrationPoint eip; Tr.Loc1.Transform(ip, eip); Tr.SetIntPoint(&ip); if (dim == 1) { nor(0) = 2*eip.x - 1.0; } else { CalcOrtho(Tr.Jacobian(), nor); } el.CalcShape(eip, shape); el.CalcDShape(eip, dshape); // compute uD through the face transformation w = ip.weight * uD->Eval(Tr, ip) / Tr.Elem1->Weight(); if (!MQ) { if (Q) { w *= Q->Eval(Tr, ip); } ni.Set(w, nor); } else { nh.Set(w, nor); MQ->Eval(mq, Tr, ip); mq.MultTranspose(nh, ni); } CalcAdjugate(Tr.Elem1->Jacobian(), adjJ); adjJ.Mult(ni, nh); dshape.Mult(nh, dshape_dn); elvect.Add(sigma, dshape_dn); if (kappa_is_nonzero) { elvect.Add(kappa*(ni*nor), shape); } } } void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, ElementTransformation &Tr, Vector &elvect) { mfem_error("DGElasticityDirichletLFIntegrator::AssembleRHSElementVect"); } void DGElasticityDirichletLFIntegrator::AssembleRHSElementVect( const FiniteElement &el, FaceElementTransformations &Tr, Vector &elvect) { MFEM_ASSERT(Tr.Elem2No < 0, "interior boundary is not supported"); #ifdef MFEM_THREAD_SAFE Vector shape; DenseMatrix dshape; DenseMatrix adjJ; DenseMatrix dshape_ps; Vector nor; Vector dshape_dn; Vector dshape_du; Vector u_dir; #endif const int dim = el.GetDim(); const int ndofs = el.GetDof(); const int nvdofs = dim*ndofs; elvect.SetSize(nvdofs); elvect = 0.0; adjJ.SetSize(dim); shape.SetSize(ndofs); dshape.SetSize(ndofs, dim); dshape_ps.SetSize(ndofs, dim); nor.SetSize(dim); dshape_dn.SetSize(ndofs); dshape_du.SetSize(ndofs); u_dir.SetSize(dim); const IntegrationRule *ir = IntRule; if (ir == NULL) { const int order = 2*el.GetOrder(); // <----- ir = &IntRules.Get(Tr.GetGeometryType(), order); } for (int pi = 0; pi < ir->GetNPoints(); ++pi) { const IntegrationPoint &ip = ir->IntPoint(pi); IntegrationPoint eip; Tr.Loc1.Transform(ip, eip); Tr.SetIntPoint(&ip); // Evaluate the Dirichlet b.c. using the face transformation. uD.Eval(u_dir, Tr, ip); el.CalcShape(eip, shape); el.CalcDShape(eip, dshape); CalcAdjugate(Tr.Elem1->Jacobian(), adjJ); Mult(dshape, adjJ, dshape_ps); if (dim == 1) { nor(0) = 2*eip.x - 1.0; } else { CalcOrtho(Tr.Jacobian(), nor); } double wL, wM, jcoef; { const double w = ip.weight / Tr.Elem1->Weight(); wL = w * lambda->Eval(*Tr.Elem1, eip); wM = w * mu->Eval(*Tr.Elem1, eip); jcoef = kappa * (wL + 2.0*wM) * (nor*nor); dshape_ps.Mult(nor, dshape_dn); dshape_ps.Mult(u_dir, dshape_du); } // alpha < uD, (lambda div(v) I + mu (grad(v) + grad(v)^T)) . n > + // + kappa < h^{-1} (lambda + 2 mu) uD, v > // i = idof + ndofs * im // v_phi(i,d) = delta(im,d) phi(idof) // div(v_phi(i)) = dphi(idof,im) // (grad(v_phi(i)))(k,l) = delta(im,k) dphi(idof,l) // // term 1: // alpha < uD, lambda div(v_phi(i)) n > // alpha lambda div(v_phi(i)) (uD.n) = // alpha lambda dphi(idof,im) (uD.n) --> quadrature --> // ip.weight/det(J1) alpha lambda (uD.nor) dshape_ps(idof,im) = // alpha * wL * (u_dir*nor) * dshape_ps(idof,im) // term 2: // < alpha uD, mu grad(v_phi(i)).n > = // alpha mu uD^T grad(v_phi(i)) n = // alpha mu uD(k) delta(im,k) dphi(idof,l) n(l) = // alpha mu uD(im) dphi(idof,l) n(l) --> quadrature --> // ip.weight/det(J1) alpha mu uD(im) dshape_ps(idof,l) nor(l) = // alpha * wM * u_dir(im) * dshape_dn(idof) // term 3: // < alpha uD, mu (grad(v_phi(i)))^T n > = // alpha mu n^T grad(v_phi(i)) uD = // alpha mu n(k) delta(im,k) dphi(idof,l) uD(l) = // alpha mu n(im) dphi(idof,l) uD(l) --> quadrature --> // ip.weight/det(J1) alpha mu nor(im) dshape_ps(idof,l) uD(l) = // alpha * wM * nor(im) * dshape_du(idof) // term j: // < kappa h^{-1} (lambda + 2 mu) uD, v_phi(i) > = // kappa/h (lambda + 2 mu) uD(k) v_phi(i,k) = // kappa/h (lambda + 2 mu) uD(k) delta(im,k) phi(idof) = // kappa/h (lambda + 2 mu) uD(im) phi(idof) --> quadrature --> // [ 1/h = |nor|/det(J1) ] // ip.weight/det(J1) |nor|^2 kappa (lambda + 2 mu) uD(im) phi(idof) = // jcoef * u_dir(im) * shape(idof) wM *= alpha; const double t1 = alpha * wL * (u_dir*nor); for (int im = 0, i = 0; im < dim; ++im) { const double t2 = wM * u_dir(im); const double t3 = wM * nor(im); const double tj = jcoef * u_dir(im); for (int idof = 0; idof < ndofs; ++idof, ++i) { elvect(i) += (t1*dshape_ps(idof,im) + t2*dshape_dn(idof) + t3*dshape_du(idof) + tj*shape(idof)); } } } } void VectorQuadratureLFIntegrator::AssembleRHSElementVect( const FiniteElement &fe, ElementTransformation &Tr, Vector &elvect) { const IntegrationRule *ir = &vqfc.GetQuadFunction().GetSpace()->GetElementIntRule(Tr.ElementNo); const int nqp = ir->GetNPoints(); const int vdim = vqfc.GetVDim(); const int ndofs = fe.GetDof(); Vector shape(ndofs); Vector temp(vdim); elvect.SetSize(vdim * ndofs); elvect = 0.0; for (int q = 0; q < nqp; q++) { const IntegrationPoint &ip = ir->IntPoint(q); Tr.SetIntPoint(&ip); const double w = Tr.Weight() * ip.weight; vqfc.Eval(temp, Tr, ip); fe.CalcShape(ip, shape); for (int ind = 0; ind < vdim; ind++) { for (int nd = 0; nd < ndofs; nd++) { elvect(nd + ind * ndofs) += w * shape(nd) * temp(ind); } } } } void QuadratureLFIntegrator::AssembleRHSElementVect(const FiniteElement &fe, ElementTransformation &Tr, Vector &elvect) { const IntegrationRule *ir = &qfc.GetQuadFunction().GetSpace()->GetElementIntRule(Tr.ElementNo); const int nqp = ir->GetNPoints(); const int ndofs = fe.GetDof(); Vector shape(ndofs); elvect.SetSize(ndofs); elvect = 0.0; for (int q = 0; q < nqp; q++) { const IntegrationPoint &ip = ir->IntPoint(q); Tr.SetIntPoint (&ip); const double w = Tr.Weight() * ip.weight; double temp = qfc.Eval(Tr, ip); fe.CalcShape(ip, shape); shape *= (w * temp); elvect += shape; } } }