#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 #include #include #include 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>>& 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 nn = std::sqrt(std::complex(eps, 0.0)); const std::complex 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 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>>& 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(std::stod(sx), 0.0); Einc(1) = std::complex(std::stod(sy), 0.0); Einc(2) = std::complex(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() { }