248 lines
6.8 KiB
C++
248 lines
6.8 KiB
C++
#include"Assemble_Base.h"
|
|
#include"../function/BF.h"
|
|
#include"../function/Gauss.h"
|
|
#include"../common/define.h"
|
|
#include"../material/Material_Base.h"
|
|
#include"../phy/Phy_Base.h"
|
|
|
|
#include<cmath>
|
|
#include<complex>
|
|
#include<string>
|
|
#include<vector>
|
|
|
|
using namespace Eigen;
|
|
|
|
// Port of MATLAB assembly_out.m and assembly_inc.m
|
|
|
|
namespace {
|
|
|
|
Vector3d crossNormal(const Vector3d& normal, const Vector3d& a)
|
|
{
|
|
return normal.cross(a.cross(normal));
|
|
}
|
|
|
|
double getScalarEps(int domainOfTet, MaterialLib* matLib)
|
|
{
|
|
return matLib->GetEpsr(domainOfTet)(0, 0).real();
|
|
}
|
|
|
|
void assembleSBCFace(
|
|
Mesh_3D* mesh,
|
|
MaterialLib* matLib,
|
|
std::vector<Triplet<std::complex<double>>>& tripleA,
|
|
VectorXcd& B,
|
|
double k0,
|
|
double* u, double* v, double* wght, int nbrGP,
|
|
BF& bfN,
|
|
bool isInc,
|
|
const Vector3cd& Einc,
|
|
int triIdx)
|
|
{
|
|
const int domain = mesh->GetDomainOfTri(triIdx);
|
|
|
|
Vector3i conn;
|
|
mesh->GetCoonOfTri(triIdx, conn);
|
|
const int numTet = conn(0);
|
|
const int numFace = conn(1) + 1;
|
|
|
|
double xv[4], yv[4], zv[4];
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
Vector3d vtx;
|
|
mesh->GetVertex(mesh->GetTet(numTet, i), vtx);
|
|
xv[i] = vtx(0); yv[i] = vtx(1); zv[i] = vtx(2);
|
|
}
|
|
|
|
Vector3d x2, y2, z2;
|
|
Vector3d x3, y3, z3;
|
|
int bfIndex[3];
|
|
int mappingIndex[3];
|
|
|
|
if (numFace == 1)
|
|
{
|
|
x2 << 1, 0, 0; y2 << 0, 1, 0; z2 << 0, 0, 1;
|
|
x3 << xv[0], xv[1], xv[2]; y3 << yv[0], yv[1], yv[2]; z3 << zv[0], zv[1], zv[2];
|
|
bfIndex[0] = 1; bfIndex[1] = 2; bfIndex[2] = 4;
|
|
mappingIndex[0] = mesh->GetEdgeOfTet(numTet, 0);
|
|
mappingIndex[1] = mesh->GetEdgeOfTet(numTet, 1);
|
|
mappingIndex[2] = mesh->GetEdgeOfTet(numTet, 3);
|
|
}
|
|
else if (numFace == 2)
|
|
{
|
|
x2 << 1, 0, 0; y2 << 0, 1, 0; z2 << 0, 0, 0;
|
|
x3 << xv[0], xv[1], xv[3]; y3 << yv[0], yv[1], yv[3]; z3 << zv[0], zv[1], zv[3];
|
|
bfIndex[0] = 1; bfIndex[1] = 3; bfIndex[2] = 5;
|
|
mappingIndex[0] = mesh->GetEdgeOfTet(numTet, 0);
|
|
mappingIndex[1] = mesh->GetEdgeOfTet(numTet, 2);
|
|
mappingIndex[2] = mesh->GetEdgeOfTet(numTet, 4);
|
|
}
|
|
else if (numFace == 3)
|
|
{
|
|
x2 << 1, 0, 0; y2 << 0, 0, 0; z2 << 0, 1, 0;
|
|
x3 << xv[0], xv[2], xv[3]; y3 << yv[0], yv[2], yv[3]; z3 << zv[0], zv[2], zv[3];
|
|
bfIndex[0] = 2; bfIndex[1] = 3; bfIndex[2] = 6;
|
|
mappingIndex[0] = mesh->GetEdgeOfTet(numTet, 1);
|
|
mappingIndex[1] = mesh->GetEdgeOfTet(numTet, 2);
|
|
mappingIndex[2] = mesh->GetEdgeOfTet(numTet, 5);
|
|
}
|
|
else if (numFace == 4)
|
|
{
|
|
x2 << 0, 0, 0; y2 << 1, 0, 0; z2 << 0, 1, 0;
|
|
x3 << xv[1], xv[2], xv[3]; y3 << yv[1], yv[2], yv[3]; z3 << zv[1], zv[2], zv[3];
|
|
bfIndex[0] = 4; bfIndex[1] = 5; bfIndex[2] = 6;
|
|
mappingIndex[0] = mesh->GetEdgeOfTet(numTet, 3);
|
|
mappingIndex[1] = mesh->GetEdgeOfTet(numTet, 4);
|
|
mappingIndex[2] = mesh->GetEdgeOfTet(numTet, 5);
|
|
}
|
|
else
|
|
{
|
|
return;
|
|
}
|
|
|
|
Matrix3d Jac;
|
|
Jac(0, 0) = xv[0] - xv[3]; Jac(0, 1) = yv[0] - yv[3]; Jac(0, 2) = zv[0] - zv[3];
|
|
Jac(1, 0) = xv[1] - xv[3]; Jac(1, 1) = yv[1] - yv[3]; Jac(1, 2) = zv[1] - zv[3];
|
|
Jac(2, 0) = xv[2] - xv[3]; Jac(2, 1) = yv[2] - yv[3]; Jac(2, 2) = zv[2] - zv[3];
|
|
const double detJ = Jac.determinant();
|
|
if (std::abs(detJ) < 1e-30)
|
|
return;
|
|
const Matrix3d InvJac = Jac.inverse();
|
|
|
|
const double a = std::sqrt((x3(0) - x3(1)) * (x3(0) - x3(1)) + (y3(0) - y3(1)) * (y3(0) - y3(1)) + (z3(0) - z3(1)) * (z3(0) - z3(1)));
|
|
const double b = std::sqrt((x3(0) - x3(2)) * (x3(0) - x3(2)) + (y3(0) - y3(2)) * (y3(0) - y3(2)) + (z3(0) - z3(2)) * (z3(0) - z3(2)));
|
|
const double c = std::sqrt((x3(1) - x3(2)) * (x3(1) - x3(2)) + (y3(1) - y3(2)) * (y3(1) - y3(2)) + (z3(1) - z3(2)) * (z3(1) - z3(2)));
|
|
double heron = (a + b + c) * (a + b - c) * (a - b + c) * (b + c - a);
|
|
if (heron < 0.0) heron = 0.0;
|
|
const double integCoe = 0.25 * std::sqrt(heron);
|
|
|
|
Vector3d normal;
|
|
mesh->GetNormOfFace(domain, normal);
|
|
|
|
Vector3d E[4][3];
|
|
for (int gp = 0; gp < nbrGP; gp++)
|
|
{
|
|
const double wgp = 1.0 - u[gp] - v[gp];
|
|
const double u2 = x2(0) * u[gp] + x2(1) * v[gp] + x2(2) * wgp;
|
|
const double v2 = y2(0) * u[gp] + y2(1) * v[gp] + y2(2) * wgp;
|
|
const double w2 = z2(0) * u[gp] + z2(1) * v[gp] + z2(2) * wgp;
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
bfN.GetValueBF(bfIndex[j], u2, v2, w2, E[gp][j]);
|
|
E[gp][j] = InvJac * E[gp][j];
|
|
}
|
|
}
|
|
|
|
const int tetDomain = mesh->GetDomainOfTet(numTet);
|
|
const double eps = getScalarEps(tetDomain, matLib);
|
|
const std::complex<double> nn = std::sqrt(std::complex<double>(eps, 0.0));
|
|
const std::complex<double> iUnit(0.0, 1.0);
|
|
|
|
Matrix3cd Ae = Matrix3cd::Zero();
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
for (int j = 0; j < 3; j++)
|
|
{
|
|
for (int gp = 0; gp < nbrGP; gp++)
|
|
{
|
|
const Vector3d tEj = crossNormal(normal, E[gp][j]);
|
|
Ae(i, j) += iUnit * k0 * nn * integCoe * wght[gp]
|
|
* E[gp][i].dot(tEj) * 2.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::complex<double> Be[3] = { 0.0, 0.0, 0.0 };
|
|
if (isInc)
|
|
{
|
|
const Vector3d EincReal(Einc.real()(0), Einc.real()(1), Einc.real()(2));
|
|
const Vector3d tEinc = crossNormal(normal, EincReal);
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
for (int gp = 0; gp < nbrGP; gp++)
|
|
{
|
|
Be[i] -= iUnit * k0 * nn * 2.0 * integCoe * wght[gp]
|
|
* E[gp][i].dot(tEinc) * 2.0;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (int i = 0; i < 3; i++)
|
|
{
|
|
for (int j = 0; j < 3; j++)
|
|
tripleA.emplace_back(mappingIndex[i], mappingIndex[j], Ae(i, j));
|
|
if (isInc)
|
|
B(mappingIndex[i]) += Be[i];
|
|
}
|
|
}
|
|
|
|
void assembleSBCByType(
|
|
Mesh_3D* mesh,
|
|
MaterialLib* matLib,
|
|
Phy_WaveOpticsModel* phy,
|
|
std::vector<Triplet<std::complex<double>>>& tripleA,
|
|
VectorXcd& B,
|
|
double k0,
|
|
int sbcTypeFilter,
|
|
bool isInc,
|
|
const Vector3cd& Einc)
|
|
{
|
|
Gauss gauss;
|
|
const int nbrGP = gauss.GetNbrGaussPoints(TWODIM, TRIANGLE, BF_LINEFUNC * 2);
|
|
double* u = new double[nbrGP];
|
|
double* v = new double[nbrGP];
|
|
double* w = new double[nbrGP];
|
|
double* wght = new double[nbrGP];
|
|
gauss.GetGaussPoints(TWODIM, TRIANGLE, u, v, w, wght);
|
|
|
|
BF bfN;
|
|
bfN.GetNbrBF(THREEDIM, TETRAHEDRON, BF_NEDELEC, BF_LINEFUNC);
|
|
const int nbrSBC = phy->GetNbrSBC();
|
|
for (int s = 0; s < nbrSBC; s++)
|
|
{
|
|
if (phy->GetSBCType(s) != sbcTypeFilter)
|
|
continue;
|
|
|
|
VectorXi triIndices;
|
|
mesh->GetTriIndicesOfDomain(phy->GetSBCDomain(s), triIndices);
|
|
for (int n = 0; n < triIndices.size(); n++)
|
|
{
|
|
assembleSBCFace(mesh, matLib, tripleA, B, k0, u, v, wght, nbrGP, bfN,
|
|
isInc, Einc, triIndices(n));
|
|
}
|
|
}
|
|
|
|
delete[] u;
|
|
delete[] v;
|
|
delete[] w;
|
|
delete[] wght;
|
|
}
|
|
|
|
} // namespace
|
|
|
|
void OpticsFEM_3D_Scatter::Assemble_SBC()
|
|
{
|
|
const double k0 = 2.0 * Pi / _mSolver->GetLda0();
|
|
|
|
assembleSBCByType(_mMesh, _mMatLib, _mPhy, _mTripleA_complex, _mB_complex,
|
|
k0, 0, false, Vector3cd::Zero());
|
|
|
|
Vector3cd Einc = Vector3cd::Zero();
|
|
for (int s = 0; s < _mPhy->GetNbrSBC(); s++)
|
|
{
|
|
if (_mPhy->GetSBCType(s) != 1)
|
|
continue;
|
|
std::string sx, sy, sz;
|
|
_mPhy->GetEinc(s, sx, sy, sz);
|
|
Einc(0) = std::complex<double>(std::stod(sx), 0.0);
|
|
Einc(1) = std::complex<double>(std::stod(sy), 0.0);
|
|
Einc(2) = std::complex<double>(std::stod(sz), 0.0);
|
|
break;
|
|
}
|
|
assembleSBCByType(_mMesh, _mMatLib, _mPhy, _mTripleA_complex, _mB_complex,
|
|
k0, 1, true, Einc);
|
|
}
|
|
|
|
void OpticsFEM_3D_Scatter::Assemble_PEC_ELE()
|
|
{
|
|
}
|