1154 lines
30 KiB
C++
1154 lines
30 KiB
C++
// Copyright (c) 2010-2025, 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 "fem.hpp"
|
|
#include <cmath>
|
|
#include "intrules.hpp"
|
|
|
|
namespace mfem
|
|
{
|
|
void LinearFormIntegrator::AssembleDevice(const FiniteElementSpace &fes,
|
|
const Array<int> &markers,
|
|
Vector &b)
|
|
{
|
|
MFEM_ABORT("Not supported.");
|
|
}
|
|
|
|
void LinearFormIntegrator::AssembleRHSElementVect(
|
|
const FiniteElement &el, FaceElementTransformations &Tr, Vector &elvect)
|
|
{
|
|
mfem_error("LinearFormIntegrator::AssembleRHSElementVect(...)");
|
|
}
|
|
|
|
void LinearFormIntegrator::AssembleRHSElementVect(
|
|
const FiniteElement &el1, const FiniteElement &el2,
|
|
FaceElementTransformations &Tr, Vector &elvect)
|
|
{
|
|
mfem_error("LinearFormIntegrator::AssembleRHSElementVect(...)");
|
|
}
|
|
|
|
DomainLFIntegrator::DomainLFIntegrator(Coefficient &QF, int a, int b)
|
|
: DeltaLFIntegrator(QF), Q(QF), oa(a), ob(b)
|
|
{
|
|
static Kernels kernels;
|
|
}
|
|
|
|
DomainLFIntegrator::DomainLFIntegrator(Coefficient &QF,
|
|
const IntegrationRule *ir)
|
|
: DeltaLFIntegrator(QF, ir), Q(QF), oa(1), ob(1)
|
|
{
|
|
static Kernels kernels;
|
|
}
|
|
|
|
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 = GetIntegrationRule(el, Tr);
|
|
|
|
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);
|
|
real_t val = Tr.Weight() * Q.Eval(Tr, ip);
|
|
|
|
el.CalcPhysShape(Tr, 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 DomainLFGradIntegrator::AssembleRHSElementVect(
|
|
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
|
{
|
|
int dof = el.GetDof();
|
|
int spaceDim = Tr.GetSpaceDim();
|
|
|
|
dshape.SetSize(dof, spaceDim);
|
|
|
|
elvect.SetSize(dof);
|
|
elvect = 0.0;
|
|
|
|
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
|
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);
|
|
el.CalcPhysDShape(Tr, dshape);
|
|
|
|
Q.Eval(Qvec, Tr, ip);
|
|
Qvec *= ip.weight * Tr.Weight();
|
|
|
|
dshape.AddMult(Qvec, elvect);
|
|
}
|
|
}
|
|
|
|
void DomainLFGradIntegrator::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();
|
|
|
|
dshape.SetSize(dof, spaceDim);
|
|
fe.CalcPhysDShape(Trans, dshape);
|
|
|
|
vec_delta->EvalDelta(Qvec, Trans, Trans.GetIntPoint());
|
|
|
|
elvect.SetSize(dof);
|
|
dshape.Mult(Qvec, elvect);
|
|
}
|
|
|
|
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);
|
|
real_t 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);
|
|
|
|
// Set the integration point in the face and the neighboring element
|
|
Tr.SetAllIntPoints(&ip);
|
|
|
|
// Access the neighboring element's integration point
|
|
const IntegrationPoint &eip = Tr.GetElement1IntPoint();
|
|
|
|
real_t 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);
|
|
if (dim > 1)
|
|
{
|
|
CalcOrtho(Tr.Jacobian(), nor);
|
|
}
|
|
else
|
|
{
|
|
nor[0] = 1.0;
|
|
}
|
|
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);
|
|
}
|
|
}
|
|
|
|
VectorDomainLFIntegrator::VectorDomainLFIntegrator(VectorCoefficient &QF,
|
|
const IntegrationRule *ir)
|
|
: DeltaLFIntegrator(QF, ir), Q(QF)
|
|
{
|
|
static DomainLFIntegrator::Kernels kernels;
|
|
}
|
|
|
|
void VectorDomainLFIntegrator::AssembleRHSElementVect(
|
|
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
|
{
|
|
int vdim = Q.GetVDim();
|
|
int dof = el.GetDof();
|
|
|
|
real_t val,cf;
|
|
|
|
shape.SetSize(dof); // vector of size dof
|
|
|
|
elvect.SetSize(dof * vdim);
|
|
elvect = 0.0;
|
|
|
|
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
|
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.CalcPhysShape(Tr, 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 VectorDomainLFGradIntegrator::AssembleRHSElementVect(
|
|
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
|
{
|
|
const int dim = el.GetDim();
|
|
const int dof = el.GetDof();
|
|
const int vdim = Q.GetVDim();
|
|
const int sdim = Tr.GetSpaceDim();
|
|
|
|
dshape.SetSize(dof,sdim);
|
|
|
|
elvect.SetSize(dof*(vdim/sdim));
|
|
elvect = 0.0;
|
|
|
|
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
|
if (ir == NULL)
|
|
{
|
|
int intorder = 2 * el.GetOrder();
|
|
ir = &IntRules.Get(el.GetGeomType(), intorder);
|
|
}
|
|
|
|
Vector pelvect(dof);
|
|
Vector part_x(dim);
|
|
|
|
for (int q = 0; q < ir->GetNPoints(); q++)
|
|
{
|
|
const IntegrationPoint &ip = ir->IntPoint(q);
|
|
|
|
Tr.SetIntPoint(&ip);
|
|
el.CalcPhysDShape(Tr, dshape);
|
|
|
|
Q.Eval(Qvec, Tr, ip);
|
|
Qvec *= ip.weight * Tr.Weight();
|
|
|
|
for (int k = 0; k < vdim/sdim; k++)
|
|
{
|
|
for (int d=0; d < sdim; ++d) { part_x(d) = Qvec(k*sdim+d); }
|
|
dshape.Mult(part_x, pelvect);
|
|
for (int s = 0; s < dof; ++s) { elvect(s+k*dof) += pelvect(s); }
|
|
}
|
|
}
|
|
}
|
|
|
|
void VectorDomainLFGradIntegrator::AssembleDeltaElementVect(
|
|
const FiniteElement&, ElementTransformation&, Vector&)
|
|
{
|
|
MFEM_ABORT("Not implemented!");
|
|
}
|
|
|
|
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);
|
|
|
|
Tr.SetIntPoint (&ip);
|
|
Q.Eval(vec, Tr, 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);
|
|
|
|
// Set the integration point in the face and the neighboring element
|
|
Tr.SetAllIntPoints(&ip);
|
|
|
|
// Access the neighboring element's integration point
|
|
const IntegrationPoint &eip = Tr.GetElement1IntPoint();
|
|
|
|
// 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();
|
|
int vdim = std::max(spaceDim, el.GetRangeDim());
|
|
|
|
vshape.SetSize(dof,vdim);
|
|
vec.SetSize(vdim);
|
|
|
|
elvect.SetSize(dof);
|
|
elvect = 0.0;
|
|
|
|
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
|
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 VectorFEDomainLFCurlIntegrator::AssembleRHSElementVect(
|
|
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
|
{
|
|
int dof = el.GetDof();
|
|
int spaceDim = Tr.GetSpaceDim();
|
|
int n=(spaceDim == 3)? spaceDim : 1;
|
|
curlshape.SetSize(dof,n);
|
|
vec.SetSize(n);
|
|
|
|
elvect.SetSize(dof);
|
|
elvect = 0.0;
|
|
|
|
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
|
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);
|
|
el.CalcPhysCurlShape(Tr, curlshape);
|
|
QF->Eval(vec, Tr, ip);
|
|
|
|
vec *= ip.weight * Tr.Weight();
|
|
curlshape.AddMult (vec, elvect);
|
|
}
|
|
}
|
|
|
|
void VectorFEDomainLFCurlIntegrator::AssembleDeltaElementVect(
|
|
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
|
|
{
|
|
int spaceDim = Trans.GetSpaceDim();
|
|
MFEM_ASSERT(vec_delta != NULL,
|
|
"coefficient must be VectorDeltaCoefficient");
|
|
int dof = fe.GetDof();
|
|
int n=(spaceDim == 3)? spaceDim : 1;
|
|
vec.SetSize(n);
|
|
curlshape.SetSize(dof, n);
|
|
elvect.SetSize(dof);
|
|
fe.CalcPhysCurlShape(Trans, curlshape);
|
|
|
|
vec_delta->EvalDelta(vec, Trans, Trans.GetIntPoint());
|
|
curlshape.Mult(vec, elvect);
|
|
}
|
|
|
|
void VectorFEDomainLFDivIntegrator::AssembleRHSElementVect(
|
|
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
|
{
|
|
int dof = el.GetDof();
|
|
|
|
divshape.SetSize(dof); // vector of size dof
|
|
elvect.SetSize(dof);
|
|
elvect = 0.0;
|
|
|
|
const IntegrationRule *ir = GetIntegrationRule(el, Tr);
|
|
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);
|
|
real_t val = Tr.Weight() * Q.Eval(Tr, ip);
|
|
el.CalcPhysDivShape(Tr, divshape);
|
|
|
|
add(elvect, ip.weight * val, divshape, elvect);
|
|
}
|
|
}
|
|
|
|
void VectorFEDomainLFDivIntegrator::AssembleDeltaElementVect(
|
|
const FiniteElement &fe, ElementTransformation &Trans, Vector &elvect)
|
|
{
|
|
MFEM_ASSERT(delta != NULL, "coefficient must be DeltaCoefficient");
|
|
elvect.SetSize(fe.GetDof());
|
|
fe.CalcPhysDivShape(Trans, elvect);
|
|
elvect *= delta->EvalDelta(Trans, Trans.GetIntPoint());
|
|
}
|
|
|
|
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);
|
|
|
|
real_t val = ip.weight;
|
|
if (F)
|
|
{
|
|
Tr.SetIntPoint (&ip);
|
|
val *= F->Eval(Tr, ip);
|
|
}
|
|
|
|
elvect.Add(val, shape);
|
|
}
|
|
}
|
|
|
|
void VectorFEBoundaryNormalLFIntegrator::AssembleRHSElementVect(
|
|
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
|
{
|
|
int dim = el.GetDim()+1;
|
|
int dof = el.GetDof();
|
|
Vector nor(dim), Fvec(dim);
|
|
|
|
shape.SetSize(dof);
|
|
elvect.SetSize(dof);
|
|
elvect = 0.0;
|
|
|
|
const IntegrationRule *ir = IntRule;
|
|
if (ir == NULL)
|
|
{
|
|
int intorder = 2 * el.GetOrder() + Tr.OrderW(); // <----------
|
|
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);
|
|
F.Eval(Fvec, Tr, ip);
|
|
real_t val = ip.weight * (Fvec*nor) / Tr.Weight();
|
|
|
|
el.CalcShape(ip, shape);
|
|
|
|
elvect.Add(val, shape);
|
|
}
|
|
}
|
|
|
|
void VectorFEBoundaryTangentLFIntegrator::AssembleRHSElementVect(
|
|
const FiniteElement &el, ElementTransformation &Tr, Vector &elvect)
|
|
{
|
|
int dof = el.GetDof();
|
|
int dim = el.GetDim();
|
|
int vdim = el.GetRangeDim();
|
|
DenseMatrix vshape(dof, vdim);
|
|
Vector f_loc(3);
|
|
Vector f_hat(2);
|
|
|
|
MFEM_VERIFY(vdim == 2, "VectorFEBoundaryTangentLFIntegrator "
|
|
"must be called with vector basis functions of dimension 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);
|
|
|
|
el.CalcVShape(ip, vshape);
|
|
|
|
Tr.SetIntPoint(&ip);
|
|
f.Eval(f_loc, Tr, ip);
|
|
|
|
if (dim == 2)
|
|
{
|
|
Tr.Jacobian().MultTranspose(f_loc, f_hat);
|
|
}
|
|
else if (dim == 1)
|
|
{
|
|
const DenseMatrix & J = Tr.Jacobian();
|
|
f_hat(0) = J(0,0) * f_loc(0) + J(1,0) * f_loc(1);
|
|
f_hat(1) = f_loc(2);
|
|
}
|
|
else
|
|
{
|
|
f_hat(0) = f_loc(1);
|
|
f_hat(1) = f_loc(2);
|
|
}
|
|
|
|
Swap<real_t>(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;
|
|
real_t 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);
|
|
|
|
// Set the integration point in the face and the neighboring element
|
|
Tr.SetAllIntPoints(&ip);
|
|
|
|
// Access the neighboring element's integration point
|
|
const IntegrationPoint &eip = Tr.GetElement1IntPoint();
|
|
el.CalcShape(eip, shape);
|
|
|
|
// 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.);
|
|
real_t 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);
|
|
|
|
// Set the integration point in the face and the neighboring element
|
|
Tr.SetAllIntPoints(&ip);
|
|
|
|
// Access the neighboring element's integration point
|
|
const IntegrationPoint &eip = Tr.GetElement1IntPoint();
|
|
|
|
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.Elem1, eip);
|
|
}
|
|
ni.Set(w, nor);
|
|
}
|
|
else
|
|
{
|
|
nh.Set(w, nor);
|
|
MQ->Eval(mq, *Tr.Elem1, eip);
|
|
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);
|
|
|
|
// Set the integration point in the face and the neighboring element
|
|
Tr.SetAllIntPoints(&ip);
|
|
|
|
// Access the neighboring element's integration point
|
|
const IntegrationPoint &eip = Tr.GetElement1IntPoint();
|
|
|
|
// 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);
|
|
}
|
|
|
|
real_t wL, wM, jcoef;
|
|
{
|
|
const real_t 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 real_t t1 = alpha * wL * (u_dir*nor);
|
|
for (int im = 0, i = 0; im < dim; ++im)
|
|
{
|
|
const real_t t2 = wM * u_dir(im);
|
|
const real_t t3 = wM * nor(im);
|
|
const real_t 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 WhiteGaussianNoiseDomainLFIntegrator::AssembleRHSElementVect
|
|
(const FiniteElement &el,
|
|
ElementTransformation &Tr,
|
|
Vector &elvect)
|
|
{
|
|
int n = el.GetDof();
|
|
elvect.SetSize(n);
|
|
for (int i = 0; i < n; i++)
|
|
{
|
|
elvect(i) = dist(generator);
|
|
}
|
|
|
|
int iel = Tr.ElementNo;
|
|
|
|
if (!save_factors || !L[iel])
|
|
{
|
|
DenseMatrix *M, m;
|
|
if (save_factors)
|
|
{
|
|
L[iel]=new DenseMatrix;
|
|
M = L[iel];
|
|
}
|
|
else
|
|
{
|
|
M = &m;
|
|
}
|
|
massinteg.AssembleElementMatrix(el, Tr, *M);
|
|
CholeskyFactors chol(M->Data());
|
|
chol.Factor(M->Height());
|
|
chol.LMult(n,1,elvect.GetData());
|
|
}
|
|
else
|
|
{
|
|
CholeskyFactors chol(L[iel]->Data());
|
|
chol.LMult(n,1,elvect.GetData());
|
|
}
|
|
}
|
|
|
|
|
|
void VectorQuadratureLFIntegrator::AssembleRHSElementVect(
|
|
const FiniteElement &fe, ElementTransformation &Tr, Vector &elvect)
|
|
{
|
|
const IntegrationRule *ir =
|
|
&vqfc.GetQuadFunction().GetSpace()->GetIntRule(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 real_t 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()->GetIntRule(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 real_t w = Tr.Weight() * ip.weight;
|
|
real_t temp = qfc.Eval(Tr, ip);
|
|
fe.CalcShape(ip, shape);
|
|
shape *= (w * temp);
|
|
elvect += shape;
|
|
}
|
|
}
|
|
|
|
}
|