817 lines
21 KiB
C++
817 lines
21 KiB
C++
// 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 "fem.hpp"
|
|
#include "../general/forall.hpp"
|
|
|
|
namespace mfem
|
|
{
|
|
|
|
void NonlinearFormIntegrator::AssemblePA(const FiniteElementSpace&)
|
|
{
|
|
mfem_error ("NonlinearFormIntegrator::AssemblePA(...)\n"
|
|
" is not implemented for this class.");
|
|
}
|
|
|
|
void NonlinearFormIntegrator::AssemblePA(const FiniteElementSpace &,
|
|
const FiniteElementSpace &)
|
|
{
|
|
mfem_error ("NonlinearFormIntegrator::AssemblePA(...)\n"
|
|
" is not implemented for this class.");
|
|
}
|
|
|
|
void NonlinearFormIntegrator::AddMultPA(const Vector &, Vector &) const
|
|
{
|
|
mfem_error ("NonlinearFormIntegrator::AddMultPA(...)\n"
|
|
" is not implemented for this class.");
|
|
}
|
|
|
|
void NonlinearFormIntegrator::AssembleElementVector(
|
|
const FiniteElement &el, ElementTransformation &Tr,
|
|
const Vector &elfun, Vector &elvect)
|
|
{
|
|
mfem_error("NonlinearFormIntegrator::AssembleElementVector"
|
|
" is not overloaded!");
|
|
}
|
|
|
|
void NonlinearFormIntegrator::AssembleFaceVector(
|
|
const FiniteElement &el1, const FiniteElement &el2,
|
|
FaceElementTransformations &Tr, const Vector &elfun, Vector &elvect)
|
|
{
|
|
mfem_error("NonlinearFormIntegrator::AssembleFaceVector"
|
|
" is not overloaded!");
|
|
}
|
|
|
|
void NonlinearFormIntegrator::AssembleElementGrad(
|
|
const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun,
|
|
DenseMatrix &elmat)
|
|
{
|
|
mfem_error("NonlinearFormIntegrator::AssembleElementGrad"
|
|
" is not overloaded!");
|
|
}
|
|
|
|
void NonlinearFormIntegrator::AssembleFaceGrad(
|
|
const FiniteElement &el1, const FiniteElement &el2,
|
|
FaceElementTransformations &Tr, const Vector &elfun,
|
|
DenseMatrix &elmat)
|
|
{
|
|
mfem_error("NonlinearFormIntegrator::AssembleFaceGrad"
|
|
" is not overloaded!");
|
|
}
|
|
|
|
double NonlinearFormIntegrator::GetElementEnergy(
|
|
const FiniteElement &el, ElementTransformation &Tr, const Vector &elfun)
|
|
{
|
|
mfem_error("NonlinearFormIntegrator::GetElementEnergy"
|
|
" is not overloaded!");
|
|
return 0.0;
|
|
}
|
|
|
|
|
|
void BlockNonlinearFormIntegrator::AssembleElementVector(
|
|
const Array<const FiniteElement *> &el,
|
|
ElementTransformation &Tr,
|
|
const Array<const Vector *> &elfun,
|
|
const Array<Vector *> &elvec)
|
|
{
|
|
mfem_error("BlockNonlinearFormIntegrator::AssembleElementVector"
|
|
" is not overloaded!");
|
|
}
|
|
|
|
void BlockNonlinearFormIntegrator::AssembleFaceVector(
|
|
const Array<const FiniteElement *> &el1,
|
|
const Array<const FiniteElement *> &el2,
|
|
FaceElementTransformations &Tr,
|
|
const Array<const Vector *> &elfun,
|
|
const Array<Vector *> &elvect)
|
|
{
|
|
mfem_error("BlockNonlinearFormIntegrator::AssembleFaceVector"
|
|
" is not overloaded!");
|
|
}
|
|
|
|
void BlockNonlinearFormIntegrator::AssembleElementGrad(
|
|
const Array<const FiniteElement*> &el,
|
|
ElementTransformation &Tr,
|
|
const Array<const Vector *> &elfun,
|
|
const Array2D<DenseMatrix *> &elmats)
|
|
{
|
|
mfem_error("BlockNonlinearFormIntegrator::AssembleElementGrad"
|
|
" is not overloaded!");
|
|
}
|
|
|
|
void BlockNonlinearFormIntegrator::AssembleFaceGrad(
|
|
const Array<const FiniteElement *>&el1,
|
|
const Array<const FiniteElement *>&el2,
|
|
FaceElementTransformations &Tr,
|
|
const Array<const Vector *> &elfun,
|
|
const Array2D<DenseMatrix *> &elmats)
|
|
{
|
|
mfem_error("BlockNonlinearFormIntegrator::AssembleFaceGrad"
|
|
" is not overloaded!");
|
|
}
|
|
|
|
double BlockNonlinearFormIntegrator::GetElementEnergy(
|
|
const Array<const FiniteElement *>&el,
|
|
ElementTransformation &Tr,
|
|
const Array<const Vector *>&elfun)
|
|
{
|
|
mfem_error("BlockNonlinearFormIntegrator::GetElementEnergy"
|
|
" is not overloaded!");
|
|
return 0.0;
|
|
}
|
|
|
|
|
|
double InverseHarmonicModel::EvalW(const DenseMatrix &J) const
|
|
{
|
|
Z.SetSize(J.Width());
|
|
CalcAdjugateTranspose(J, Z);
|
|
return 0.5*(Z*Z)/J.Det();
|
|
}
|
|
|
|
void InverseHarmonicModel::EvalP(const DenseMatrix &J, DenseMatrix &P) const
|
|
{
|
|
int dim = J.Width();
|
|
double t;
|
|
|
|
Z.SetSize(dim);
|
|
S.SetSize(dim);
|
|
CalcAdjugateTranspose(J, Z);
|
|
MultAAt(Z, S);
|
|
t = 0.5*S.Trace();
|
|
for (int i = 0; i < dim; i++)
|
|
{
|
|
S(i,i) -= t;
|
|
}
|
|
t = J.Det();
|
|
S *= -1.0/(t*t);
|
|
Mult(S, Z, P);
|
|
}
|
|
|
|
void InverseHarmonicModel::AssembleH(
|
|
const DenseMatrix &J, const DenseMatrix &DS, const double weight,
|
|
DenseMatrix &A) const
|
|
{
|
|
int dof = DS.Height(), dim = DS.Width();
|
|
double t;
|
|
|
|
Z.SetSize(dim);
|
|
S.SetSize(dim);
|
|
G.SetSize(dof, dim);
|
|
C.SetSize(dof, dim);
|
|
|
|
CalcAdjugateTranspose(J, Z);
|
|
MultAAt(Z, S);
|
|
|
|
t = 1.0/J.Det();
|
|
Z *= t; // Z = J^{-t}
|
|
S *= t; // S = |J| (J.J^t)^{-1}
|
|
t = 0.5*S.Trace();
|
|
|
|
MultABt(DS, Z, G); // G = DS.J^{-1}
|
|
Mult(G, S, C);
|
|
|
|
// 1.
|
|
for (int i = 0; i < dof; i++)
|
|
for (int j = 0; j <= i; j++)
|
|
{
|
|
double a = 0.0;
|
|
for (int d = 0; d < dim; d++)
|
|
{
|
|
a += G(i,d)*G(j,d);
|
|
}
|
|
a *= weight;
|
|
for (int k = 0; k < dim; k++)
|
|
for (int l = 0; l <= k; l++)
|
|
{
|
|
double b = a*S(k,l);
|
|
A(i+k*dof,j+l*dof) += b;
|
|
if (i != j)
|
|
{
|
|
A(j+k*dof,i+l*dof) += b;
|
|
}
|
|
if (k != l)
|
|
{
|
|
A(i+l*dof,j+k*dof) += b;
|
|
if (i != j)
|
|
{
|
|
A(j+l*dof,i+k*dof) += b;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// 2.
|
|
for (int i = 1; i < dof; i++)
|
|
for (int j = 0; j < i; j++)
|
|
{
|
|
for (int k = 1; k < dim; k++)
|
|
for (int l = 0; l < k; l++)
|
|
{
|
|
double a =
|
|
weight*(C(i,l)*G(j,k) - C(i,k)*G(j,l) +
|
|
C(j,k)*G(i,l) - C(j,l)*G(i,k) +
|
|
t*(G(i,k)*G(j,l) - G(i,l)*G(j,k)));
|
|
|
|
A(i+k*dof,j+l*dof) += a;
|
|
A(j+l*dof,i+k*dof) += a;
|
|
|
|
A(i+l*dof,j+k*dof) -= a;
|
|
A(j+k*dof,i+l*dof) -= a;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
inline void NeoHookeanModel::EvalCoeffs() const
|
|
{
|
|
mu = c_mu->Eval(*Ttr, Ttr->GetIntPoint());
|
|
K = c_K->Eval(*Ttr, Ttr->GetIntPoint());
|
|
if (c_g)
|
|
{
|
|
g = c_g->Eval(*Ttr, Ttr->GetIntPoint());
|
|
}
|
|
}
|
|
|
|
double NeoHookeanModel::EvalW(const DenseMatrix &J) const
|
|
{
|
|
int dim = J.Width();
|
|
|
|
if (have_coeffs)
|
|
{
|
|
EvalCoeffs();
|
|
}
|
|
|
|
double dJ = J.Det();
|
|
double sJ = dJ/g;
|
|
double bI1 = pow(dJ, -2.0/dim)*(J*J); // \bar{I}_1
|
|
|
|
return 0.5*(mu*(bI1 - dim) + K*(sJ - 1.0)*(sJ - 1.0));
|
|
}
|
|
|
|
void NeoHookeanModel::EvalP(const DenseMatrix &J, DenseMatrix &P) const
|
|
{
|
|
int dim = J.Width();
|
|
|
|
if (have_coeffs)
|
|
{
|
|
EvalCoeffs();
|
|
}
|
|
|
|
Z.SetSize(dim);
|
|
CalcAdjugateTranspose(J, Z);
|
|
|
|
double dJ = J.Det();
|
|
double a = mu*pow(dJ, -2.0/dim);
|
|
double b = K*(dJ/g - 1.0)/g - a*(J*J)/(dim*dJ);
|
|
|
|
P = 0.0;
|
|
P.Add(a, J);
|
|
P.Add(b, Z);
|
|
}
|
|
|
|
void NeoHookeanModel::AssembleH(const DenseMatrix &J, const DenseMatrix &DS,
|
|
const double weight, DenseMatrix &A) const
|
|
{
|
|
int dof = DS.Height(), dim = DS.Width();
|
|
|
|
if (have_coeffs)
|
|
{
|
|
EvalCoeffs();
|
|
}
|
|
|
|
Z.SetSize(dim);
|
|
G.SetSize(dof, dim);
|
|
C.SetSize(dof, dim);
|
|
|
|
double dJ = J.Det();
|
|
double sJ = dJ/g;
|
|
double a = mu*pow(dJ, -2.0/dim);
|
|
double bc = a*(J*J)/dim;
|
|
double b = bc - K*sJ*(sJ - 1.0);
|
|
double c = 2.0*bc/dim + K*sJ*(2.0*sJ - 1.0);
|
|
|
|
CalcAdjugateTranspose(J, Z);
|
|
Z *= (1.0/dJ); // Z = J^{-t}
|
|
|
|
MultABt(DS, J, C); // C = DS J^t
|
|
MultABt(DS, Z, G); // G = DS J^{-1}
|
|
|
|
a *= weight;
|
|
b *= weight;
|
|
c *= weight;
|
|
|
|
// 1.
|
|
for (int i = 0; i < dof; i++)
|
|
for (int k = 0; k <= i; k++)
|
|
{
|
|
double s = 0.0;
|
|
for (int d = 0; d < dim; d++)
|
|
{
|
|
s += DS(i,d)*DS(k,d);
|
|
}
|
|
s *= a;
|
|
|
|
for (int d = 0; d < dim; d++)
|
|
{
|
|
A(i+d*dof,k+d*dof) += s;
|
|
}
|
|
|
|
if (k != i)
|
|
for (int d = 0; d < dim; d++)
|
|
{
|
|
A(k+d*dof,i+d*dof) += s;
|
|
}
|
|
}
|
|
|
|
a *= (-2.0/dim);
|
|
|
|
// 2.
|
|
for (int i = 0; i < dof; i++)
|
|
for (int j = 0; j < dim; j++)
|
|
for (int k = 0; k < dof; k++)
|
|
for (int l = 0; l < dim; l++)
|
|
{
|
|
A(i+j*dof,k+l*dof) +=
|
|
a*(C(i,j)*G(k,l) + G(i,j)*C(k,l)) +
|
|
b*G(i,l)*G(k,j) + c*G(i,j)*G(k,l);
|
|
}
|
|
}
|
|
|
|
|
|
double HyperelasticNLFIntegrator::GetElementEnergy(const FiniteElement &el,
|
|
ElementTransformation &Ttr,
|
|
const Vector &elfun)
|
|
{
|
|
int dof = el.GetDof(), dim = el.GetDim();
|
|
double energy;
|
|
|
|
DSh.SetSize(dof, dim);
|
|
Jrt.SetSize(dim);
|
|
Jpr.SetSize(dim);
|
|
Jpt.SetSize(dim);
|
|
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
|
|
|
const IntegrationRule *ir = IntRule;
|
|
if (!ir)
|
|
{
|
|
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
|
|
}
|
|
|
|
energy = 0.0;
|
|
model->SetTransformation(Ttr);
|
|
for (int i = 0; i < ir->GetNPoints(); i++)
|
|
{
|
|
const IntegrationPoint &ip = ir->IntPoint(i);
|
|
Ttr.SetIntPoint(&ip);
|
|
CalcInverse(Ttr.Jacobian(), Jrt);
|
|
|
|
el.CalcDShape(ip, DSh);
|
|
MultAtB(PMatI, DSh, Jpr);
|
|
Mult(Jpr, Jrt, Jpt);
|
|
|
|
energy += ip.weight * Ttr.Weight() * model->EvalW(Jpt);
|
|
}
|
|
|
|
return energy;
|
|
}
|
|
|
|
void HyperelasticNLFIntegrator::AssembleElementVector(
|
|
const FiniteElement &el, ElementTransformation &Ttr,
|
|
const Vector &elfun, Vector &elvect)
|
|
{
|
|
int dof = el.GetDof(), dim = el.GetDim();
|
|
|
|
DSh.SetSize(dof, dim);
|
|
DS.SetSize(dof, dim);
|
|
Jrt.SetSize(dim);
|
|
Jpt.SetSize(dim);
|
|
P.SetSize(dim);
|
|
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
|
elvect.SetSize(dof*dim);
|
|
PMatO.UseExternalData(elvect.GetData(), dof, dim);
|
|
|
|
const IntegrationRule *ir = IntRule;
|
|
if (!ir)
|
|
{
|
|
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
|
|
}
|
|
|
|
elvect = 0.0;
|
|
model->SetTransformation(Ttr);
|
|
for (int i = 0; i < ir->GetNPoints(); i++)
|
|
{
|
|
const IntegrationPoint &ip = ir->IntPoint(i);
|
|
Ttr.SetIntPoint(&ip);
|
|
CalcInverse(Ttr.Jacobian(), Jrt);
|
|
|
|
el.CalcDShape(ip, DSh);
|
|
Mult(DSh, Jrt, DS);
|
|
MultAtB(PMatI, DS, Jpt);
|
|
|
|
model->EvalP(Jpt, P);
|
|
|
|
P *= ip.weight * Ttr.Weight();
|
|
AddMultABt(DS, P, PMatO);
|
|
}
|
|
}
|
|
|
|
void HyperelasticNLFIntegrator::AssembleElementGrad(const FiniteElement &el,
|
|
ElementTransformation &Ttr,
|
|
const Vector &elfun,
|
|
DenseMatrix &elmat)
|
|
{
|
|
int dof = el.GetDof(), dim = el.GetDim();
|
|
|
|
DSh.SetSize(dof, dim);
|
|
DS.SetSize(dof, dim);
|
|
Jrt.SetSize(dim);
|
|
Jpt.SetSize(dim);
|
|
PMatI.UseExternalData(elfun.GetData(), dof, dim);
|
|
elmat.SetSize(dof*dim);
|
|
|
|
const IntegrationRule *ir = IntRule;
|
|
if (!ir)
|
|
{
|
|
ir = &(IntRules.Get(el.GetGeomType(), 2*el.GetOrder() + 3)); // <---
|
|
}
|
|
|
|
elmat = 0.0;
|
|
model->SetTransformation(Ttr);
|
|
for (int i = 0; i < ir->GetNPoints(); i++)
|
|
{
|
|
const IntegrationPoint &ip = ir->IntPoint(i);
|
|
Ttr.SetIntPoint(&ip);
|
|
CalcInverse(Ttr.Jacobian(), Jrt);
|
|
|
|
el.CalcDShape(ip, DSh);
|
|
Mult(DSh, Jrt, DS);
|
|
MultAtB(PMatI, DS, Jpt);
|
|
|
|
model->AssembleH(Jpt, DS, ip.weight * Ttr.Weight(), elmat);
|
|
}
|
|
}
|
|
|
|
double IncompressibleNeoHookeanIntegrator::GetElementEnergy(
|
|
const Array<const FiniteElement *>&el,
|
|
ElementTransformation &Tr,
|
|
const Array<const Vector *>&elfun)
|
|
{
|
|
if (el.Size() != 2)
|
|
{
|
|
mfem_error("IncompressibleNeoHookeanIntegrator::GetElementEnergy"
|
|
" has incorrect block finite element space size!");
|
|
}
|
|
|
|
int dof_u = el[0]->GetDof();
|
|
int dim = el[0]->GetDim();
|
|
|
|
DSh_u.SetSize(dof_u, dim);
|
|
J0i.SetSize(dim);
|
|
J1.SetSize(dim);
|
|
J.SetSize(dim);
|
|
PMatI_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
|
|
|
|
int intorder = 2*el[0]->GetOrder() + 3; // <---
|
|
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
|
|
|
|
double energy = 0.0;
|
|
double mu = 0.0;
|
|
|
|
for (int i = 0; i < ir.GetNPoints(); ++i)
|
|
{
|
|
const IntegrationPoint &ip = ir.IntPoint(i);
|
|
Tr.SetIntPoint(&ip);
|
|
CalcInverse(Tr.Jacobian(), J0i);
|
|
|
|
el[0]->CalcDShape(ip, DSh_u);
|
|
MultAtB(PMatI_u, DSh_u, J1);
|
|
Mult(J1, J0i, J);
|
|
|
|
mu = c_mu->Eval(Tr, ip);
|
|
|
|
energy += ip.weight*Tr.Weight()*(mu/2.0)*(J*J - 3);
|
|
}
|
|
|
|
return energy;
|
|
}
|
|
|
|
void IncompressibleNeoHookeanIntegrator::AssembleElementVector(
|
|
const Array<const FiniteElement *> &el,
|
|
ElementTransformation &Tr,
|
|
const Array<const Vector *> &elfun,
|
|
const Array<Vector *> &elvec)
|
|
{
|
|
if (el.Size() != 2)
|
|
{
|
|
mfem_error("IncompressibleNeoHookeanIntegrator::AssembleElementVector"
|
|
" has finite element space of incorrect block number");
|
|
}
|
|
|
|
int dof_u = el[0]->GetDof();
|
|
int dof_p = el[1]->GetDof();
|
|
|
|
int dim = el[0]->GetDim();
|
|
int spaceDim = Tr.GetSpaceDim();
|
|
|
|
if (dim != spaceDim)
|
|
{
|
|
mfem_error("IncompressibleNeoHookeanIntegrator::AssembleElementVector"
|
|
" is not defined on manifold meshes");
|
|
}
|
|
|
|
|
|
DSh_u.SetSize(dof_u, dim);
|
|
DS_u.SetSize(dof_u, dim);
|
|
J0i.SetSize(dim);
|
|
F.SetSize(dim);
|
|
FinvT.SetSize(dim);
|
|
P.SetSize(dim);
|
|
PMatI_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
|
|
elvec[0]->SetSize(dof_u*dim);
|
|
PMatO_u.UseExternalData(elvec[0]->GetData(), dof_u, dim);
|
|
|
|
Sh_p.SetSize(dof_p);
|
|
elvec[1]->SetSize(dof_p);
|
|
|
|
int intorder = 2*el[0]->GetOrder() + 3; // <---
|
|
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
|
|
|
|
*elvec[0] = 0.0;
|
|
*elvec[1] = 0.0;
|
|
|
|
for (int i = 0; i < ir.GetNPoints(); ++i)
|
|
{
|
|
const IntegrationPoint &ip = ir.IntPoint(i);
|
|
Tr.SetIntPoint(&ip);
|
|
CalcInverse(Tr.Jacobian(), J0i);
|
|
|
|
el[0]->CalcDShape(ip, DSh_u);
|
|
Mult(DSh_u, J0i, DS_u);
|
|
MultAtB(PMatI_u, DS_u, F);
|
|
|
|
el[1]->CalcShape(ip, Sh_p);
|
|
|
|
double pres = Sh_p * *elfun[1];
|
|
double mu = c_mu->Eval(Tr, ip);
|
|
double dJ = F.Det();
|
|
|
|
CalcInverseTranspose(F, FinvT);
|
|
|
|
P = 0.0;
|
|
P.Add(mu * dJ, F);
|
|
P.Add(-1.0 * pres * dJ, FinvT);
|
|
P *= ip.weight*Tr.Weight();
|
|
|
|
AddMultABt(DS_u, P, PMatO_u);
|
|
|
|
elvec[1]->Add(ip.weight * Tr.Weight() * (dJ - 1.0), Sh_p);
|
|
}
|
|
|
|
}
|
|
|
|
void IncompressibleNeoHookeanIntegrator::AssembleElementGrad(
|
|
const Array<const FiniteElement*> &el,
|
|
ElementTransformation &Tr,
|
|
const Array<const Vector *> &elfun,
|
|
const Array2D<DenseMatrix *> &elmats)
|
|
{
|
|
int dof_u = el[0]->GetDof();
|
|
int dof_p = el[1]->GetDof();
|
|
|
|
int dim = el[0]->GetDim();
|
|
|
|
elmats(0,0)->SetSize(dof_u*dim, dof_u*dim);
|
|
elmats(0,1)->SetSize(dof_u*dim, dof_p);
|
|
elmats(1,0)->SetSize(dof_p, dof_u*dim);
|
|
elmats(1,1)->SetSize(dof_p, dof_p);
|
|
|
|
*elmats(0,0) = 0.0;
|
|
*elmats(0,1) = 0.0;
|
|
*elmats(1,0) = 0.0;
|
|
*elmats(1,1) = 0.0;
|
|
|
|
DSh_u.SetSize(dof_u, dim);
|
|
DS_u.SetSize(dof_u, dim);
|
|
J0i.SetSize(dim);
|
|
F.SetSize(dim);
|
|
FinvT.SetSize(dim);
|
|
Finv.SetSize(dim);
|
|
P.SetSize(dim);
|
|
PMatI_u.UseExternalData(elfun[0]->GetData(), dof_u, dim);
|
|
Sh_p.SetSize(dof_p);
|
|
|
|
int intorder = 2*el[0]->GetOrder() + 3; // <---
|
|
const IntegrationRule &ir = IntRules.Get(el[0]->GetGeomType(), intorder);
|
|
|
|
for (int i = 0; i < ir.GetNPoints(); ++i)
|
|
{
|
|
const IntegrationPoint &ip = ir.IntPoint(i);
|
|
Tr.SetIntPoint(&ip);
|
|
CalcInverse(Tr.Jacobian(), J0i);
|
|
|
|
el[0]->CalcDShape(ip, DSh_u);
|
|
Mult(DSh_u, J0i, DS_u);
|
|
MultAtB(PMatI_u, DS_u, F);
|
|
|
|
el[1]->CalcShape(ip, Sh_p);
|
|
double pres = Sh_p * *elfun[1];
|
|
double mu = c_mu->Eval(Tr, ip);
|
|
double dJ = F.Det();
|
|
double dJ_FinvT_DS;
|
|
|
|
CalcInverseTranspose(F, FinvT);
|
|
|
|
// u,u block
|
|
for (int i_u = 0; i_u < dof_u; ++i_u)
|
|
{
|
|
for (int i_dim = 0; i_dim < dim; ++i_dim)
|
|
{
|
|
for (int j_u = 0; j_u < dof_u; ++j_u)
|
|
{
|
|
for (int j_dim = 0; j_dim < dim; ++j_dim)
|
|
{
|
|
|
|
// m = j_dim;
|
|
// k = i_dim;
|
|
|
|
for (int n=0; n<dim; ++n)
|
|
{
|
|
for (int l=0; l<dim; ++l)
|
|
{
|
|
(*elmats(0,0))(i_u + i_dim*dof_u, j_u + j_dim*dof_u) +=
|
|
dJ * (mu * F(i_dim, l) - pres * FinvT(i_dim,l)) *
|
|
FinvT(j_dim,n) * DS_u(i_u,l) * DS_u(j_u, n) *
|
|
ip.weight * Tr.Weight();
|
|
|
|
if (j_dim == i_dim && n==l)
|
|
{
|
|
(*elmats(0,0))(i_u + i_dim*dof_u, j_u + j_dim*dof_u) +=
|
|
dJ * mu * DS_u(i_u, l) * DS_u(j_u,n) *
|
|
ip.weight * Tr.Weight();
|
|
}
|
|
|
|
// a = n;
|
|
// b = m;
|
|
(*elmats(0,0))(i_u + i_dim*dof_u, j_u + j_dim*dof_u) +=
|
|
dJ * pres * FinvT(i_dim, n) *
|
|
FinvT(j_dim,l) * DS_u(i_u,l) * DS_u(j_u,n) *
|
|
ip.weight * Tr.Weight();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// u,p and p,u blocks
|
|
for (int i_p = 0; i_p < dof_p; ++i_p)
|
|
{
|
|
for (int j_u = 0; j_u < dof_u; ++j_u)
|
|
{
|
|
for (int dim_u = 0; dim_u < dim; ++dim_u)
|
|
{
|
|
for (int l=0; l<dim; ++l)
|
|
{
|
|
dJ_FinvT_DS = dJ * FinvT(dim_u,l) * DS_u(j_u, l) * Sh_p(i_p) *
|
|
ip.weight * Tr.Weight();
|
|
(*elmats(1,0))(i_p, j_u + dof_u * dim_u) += dJ_FinvT_DS;
|
|
(*elmats(0,1))(j_u + dof_u * dim_u, i_p) -= dJ_FinvT_DS;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
const IntegrationRule&
|
|
VectorConvectionNLFIntegrator::GetRule(const FiniteElement &fe,
|
|
ElementTransformation &T)
|
|
{
|
|
const int order = 2 * fe.GetOrder() + T.OrderGrad(&fe);
|
|
return IntRules.Get(fe.GetGeomType(), order);
|
|
}
|
|
|
|
void VectorConvectionNLFIntegrator::AssembleElementVector(
|
|
const FiniteElement &el,
|
|
ElementTransformation &T,
|
|
const Vector &elfun,
|
|
Vector &elvect)
|
|
{
|
|
const int nd = el.GetDof();
|
|
const int dim = el.GetDim();
|
|
|
|
shape.SetSize(nd);
|
|
dshape.SetSize(nd, dim);
|
|
elvect.SetSize(nd * dim);
|
|
gradEF.SetSize(dim);
|
|
|
|
EF.UseExternalData(elfun.GetData(), nd, dim);
|
|
ELV.UseExternalData(elvect.GetData(), nd, dim);
|
|
|
|
Vector vec1(dim), vec2(dim);
|
|
const IntegrationRule *ir = IntRule ? IntRule : &GetRule(el, T);
|
|
ELV = 0.0;
|
|
for (int i = 0; i < ir->GetNPoints(); i++)
|
|
{
|
|
const IntegrationPoint &ip = ir->IntPoint(i);
|
|
T.SetIntPoint(&ip);
|
|
el.CalcShape(ip, shape);
|
|
el.CalcPhysDShape(T, dshape);
|
|
double w = ip.weight * T.Weight();
|
|
if (Q) { w *= Q->Eval(T, ip); }
|
|
MultAtB(EF, dshape, gradEF);
|
|
EF.MultTranspose(shape, vec1);
|
|
gradEF.Mult(vec1, vec2);
|
|
vec2 *= w;
|
|
AddMultVWt(shape, vec2, ELV);
|
|
}
|
|
}
|
|
|
|
void VectorConvectionNLFIntegrator::AssembleElementGrad(
|
|
const FiniteElement &el,
|
|
ElementTransformation &trans,
|
|
const Vector &elfun,
|
|
DenseMatrix &elmat)
|
|
{
|
|
int nd = el.GetDof();
|
|
int dim = el.GetDim();
|
|
|
|
shape.SetSize(nd);
|
|
dshape.SetSize(nd, dim);
|
|
dshapex.SetSize(nd, dim);
|
|
elmat.SetSize(nd * dim);
|
|
elmat_comp.SetSize(nd);
|
|
gradEF.SetSize(dim);
|
|
|
|
EF.UseExternalData(elfun.GetData(), nd, dim);
|
|
|
|
double w;
|
|
Vector vec1(dim), vec2(dim), vec3(nd);
|
|
|
|
const IntegrationRule *ir = IntRule;
|
|
if (ir == nullptr)
|
|
{
|
|
int order = 2 * el.GetOrder() + trans.OrderGrad(&el);
|
|
ir = &IntRules.Get(el.GetGeomType(), order);
|
|
}
|
|
|
|
elmat = 0.0;
|
|
for (int i = 0; i < ir->GetNPoints(); i++)
|
|
{
|
|
const IntegrationPoint &ip = ir->IntPoint(i);
|
|
trans.SetIntPoint(&ip);
|
|
|
|
el.CalcShape(ip, shape);
|
|
el.CalcDShape(ip, dshape);
|
|
|
|
Mult(dshape, trans.InverseJacobian(), dshapex);
|
|
|
|
w = ip.weight;
|
|
|
|
if (Q)
|
|
{
|
|
w *= Q->Eval(trans, ip);
|
|
}
|
|
|
|
MultAtB(EF, dshapex, gradEF);
|
|
EF.MultTranspose(shape, vec1);
|
|
|
|
trans.AdjugateJacobian().Mult(vec1, vec2);
|
|
|
|
vec2 *= w;
|
|
dshape.Mult(vec2, vec3);
|
|
MultVWt(shape, vec3, elmat_comp);
|
|
|
|
for (int i = 0; i < dim; i++)
|
|
{
|
|
elmat.AddMatrix(elmat_comp, i * nd, i * nd);
|
|
}
|
|
|
|
MultVVt(shape, elmat_comp);
|
|
w = ip.weight * trans.Weight();
|
|
if (Q)
|
|
{
|
|
w *= Q->Eval(trans, ip);
|
|
}
|
|
for (int i = 0; i < dim; i++)
|
|
{
|
|
for (int j = 0; j < dim; j++)
|
|
{
|
|
elmat.AddMatrix(w * gradEF(i, j), elmat_comp, i * nd, j * nd);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|