XIAN-FEM-2026June/3D opticsfem-master/kernel/Assemble_Scatter_3D_Boundar...

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()
{
}