#include"Mesh_Base.h" #include"../common/util.h" #include #include #include #include #include #include //get edges with edge's flag of domain void Mesh_2D::GetIndexOfDomain(Eigen::VectorXi domain, Eigen::VectorXi& nodeIndex, Eigen::VectorXi& edgeIndex) { int NbrEdges = 0; int NbrDomain = domain.rows(); for (int i = 0; i < NbrDomain; i++) { for (int j = 0; j < _mNbrEdges; j++) { if (GetDomainOfEdges(j) == domain(i)) NbrEdges++; } } //store edgeIndex and nodeIndex Eigen::Vector2i coonOfEdges; int* tempEdgeIndex, * tempNodeIndex; tempEdgeIndex = new int[NbrEdges]; tempNodeIndex = new int[NbrEdges * 2]; int numNode = 0; int numEdge = 0; for (int i = 0; i < NbrDomain; i++) { for (int j = 0; j < _mNbrEdges; j++) { if (GetDomainOfEdges(j) == domain(i)) { this->GetCoonOfEdges(j, coonOfEdges); //coonOfEdges 0:tri 1:numOfEdge tempEdgeIndex[numEdge] = GetEdgeOfTri(coonOfEdges(0), coonOfEdges(1)); numEdge++; tempNodeIndex[numNode] = GetEdge(GetEdgeOfTri(coonOfEdges(0), coonOfEdges(1)), 0); numNode++; tempNodeIndex[numNode] = GetEdge(GetEdgeOfTri(coonOfEdges(0), coonOfEdges(1)), 1); numNode++; } } } //sort and unique nodeIndex std::sort(tempNodeIndex, tempNodeIndex + NbrEdges * 2); int NbrNodes = (std::unique(tempNodeIndex, tempNodeIndex + NbrEdges * 2) - tempNodeIndex); nodeIndex = Eigen::VectorXi::Zero(NbrNodes); for (int i = 0; i < NbrNodes; i++) nodeIndex(i) = tempNodeIndex[i]; //sort edgeIndex edgeIndex = Eigen::VectorXi::Zero(NbrEdges); std::sort(tempEdgeIndex, tempEdgeIndex + NbrEdges); for (int i = 0; i < NbrEdges; i++) edgeIndex(i) = tempEdgeIndex[i]; delete[] tempEdgeIndex, tempNodeIndex; } void Mesh_2D::GetIndexOfDomain2(Eigen::VectorXi domain, Eigen::VectorXi& edgeIndex, Eigen::VectorXi& edgeNum) { int NbrEdges = 0; int NbrDomain = domain.rows(); for (int i = 0; i < NbrDomain; i++) { for (int j = 0; j < _mNbrEdges; j++) { if (GetDomainOfEdges(j) == domain(i)) NbrEdges++; } } //store edgeIndex edgeIndex = Eigen::VectorXi::Zero(NbrEdges); edgeNum = Eigen::VectorXi::Zero(NbrEdges); int numEdge = 0; for (int i = 0; i < NbrDomain; i++) { for (int j = 0; j < _mNbrEdges; j++) { if (GetDomainOfEdges(j) == domain(i)) { edgeIndex(numEdge) = j; edgeNum(numEdge) = i; numEdge++; } } } } namespace { void appendFaceEdgesOfTri(Mesh_3D* mesh, int triIdx, std::vector& edges) { Eigen::Vector3i conn; mesh->GetCoonOfTri(triIdx, conn); const int numTet = conn(0); const int numFace = conn(1) + 1; int e0 = 0, e1 = 0, e2 = 0; if (numFace == 1) { e0 = mesh->GetEdgeOfTet(numTet, 0); e1 = mesh->GetEdgeOfTet(numTet, 1); e2 = mesh->GetEdgeOfTet(numTet, 3); } else if (numFace == 2) { e0 = mesh->GetEdgeOfTet(numTet, 0); e1 = mesh->GetEdgeOfTet(numTet, 2); e2 = mesh->GetEdgeOfTet(numTet, 4); } else if (numFace == 3) { e0 = mesh->GetEdgeOfTet(numTet, 1); e1 = mesh->GetEdgeOfTet(numTet, 2); e2 = mesh->GetEdgeOfTet(numTet, 5); } else if (numFace == 4) { e0 = mesh->GetEdgeOfTet(numTet, 3); e1 = mesh->GetEdgeOfTet(numTet, 4); e2 = mesh->GetEdgeOfTet(numTet, 5); } else { return; } edges.push_back(e0); edges.push_back(e1); edges.push_back(e2); } void collectEdgesOnDomains(Mesh_3D* mesh, const Eigen::VectorXi& domains, std::vector& edges) { // Mirror MATLAB findTri + edge collect: gather/sort tris, then unique edges. std::vector triIndex; for (int d = 0; d < domains.size(); d++) { const int domainId = domains(d); for (int j = 0; j < mesh->GetNbrTri(); j++) { if (mesh->GetDomainOfTri(j) == domainId) triIndex.push_back(j); } } std::sort(triIndex.begin(), triIndex.end()); for (int j : triIndex) appendFaceEdgesOfTri(mesh, j, edges); std::sort(edges.begin(), edges.end()); edges.erase(std::unique(edges.begin(), edges.end()), edges.end()); } void getEdgeVertices(Mesh_3D* mesh, int edgeId, Eigen::Vector3d& p0, Eigen::Vector3d& p1) { mesh->GetVertex(mesh->GetEdge(edgeId, 0), p0); mesh->GetVertex(mesh->GetEdge(edgeId, 1), p1); } bool matchEdgePair(Mesh_3D* mesh, int srcEdge, int dstEdge, double theta, double tol, int& signOut) { Eigen::Vector3d v1, v2, v3, v4; getEdgeVertices(mesh, srcEdge, v1, v2); getEdgeVertices(mesh, dstEdge, v3, v4); Eigen::Matrix3d traMat; traMat << std::cos(theta), -std::sin(theta), 0.0, std::sin(theta), std::cos(theta), 0.0, 0.0, 0.0, 1.0; v3 = traMat * v3; v4 = traMat * v4; const double l1 = (v1 - v3).norm(); const double l2 = (v2 - v4).norm(); const double l3 = (v1 - v4).norm(); const double l4 = (v2 - v3).norm(); if (l1 + l2 < tol) { signOut = 1; return true; } if (l3 + l4 < tol) { signOut = -1; return true; } return false; } // --------------------------------------------------------------------------- // PBC pairing — mirrors MATLAB: // order1 translation: matlab 3D一阶基+散射边界条件+周期边界/findPBCIndex.m // order2 faces: matlab 3D二阶基+...+单周期边界/findPBCIndex.m (face // branch), with translation instead of rotation. // --------------------------------------------------------------------------- static double matlabPbcTol(const Eigen::Vector3d& dis) { // order1: err = norm(dis)*5e-5 (keep bit-identical for validated order1) const double dl = dis.norm(); return (dl > 0.0) ? dl * 0.00005 : 0.01 * 0.00005; } static double matlabFacePbcTol(const Eigen::Vector3d& dis) { // order2 face branch hardcodes dl=0.01 → err=5e-7. For µm translation // periods, norm(dis)*5e-5 is ~1e-10 and rejects true pairs; keep the // order2 floor while still scaling with larger periods. const double dl = dis.norm(); const double rel = (dl > 0.0) ? dl * 0.00005 : 0.0; return std::max(rel, 0.01 * 0.00005); } bool matchEdgePairTranslation(Mesh_3D* mesh, int srcEdge, int dstEdge, const Eigen::Vector3d& dis, double tol, int& signOut) { // MATLAB: l1=|‖v1−v3‖−dl|, l2=|‖v2−v4‖−dl|; flip uses (v1,v4)/(v2,v3). Eigen::Vector3d v1, v2, v3, v4; getEdgeVertices(mesh, srcEdge, v1, v2); getEdgeVertices(mesh, dstEdge, v3, v4); const double dl = dis.norm(); const double l1 = std::abs((v1 - v3).norm() - dl); const double l2 = std::abs((v2 - v4).norm() - dl); const double l3 = std::abs((v1 - v4).norm() - dl); const double l4 = std::abs((v2 - v3).norm() - dl); if ((l1 + l2) < tol) { signOut = 1; return true; } if ((l3 + l4) < tol) { signOut = -1; return true; } return false; } void pairEdgesByTranslation(Mesh_3D* mesh, const std::vector& srcEdges, const std::vector& dstEdges, const Eigen::Vector3d& dis, std::vector& pairedSrc, std::vector& pairedDst, std::vector& pairedSign, bool useFaceStyleTolFloor = false) { const double tol = useFaceStyleTolFloor ? matlabFacePbcTol(dis) : matlabPbcTol(dis); if (!useFaceStyleTolFloor) { // Order-1: MATLAB first-match, no destination locking (bit-identical). for (int srcEdge : srcEdges) { bool matched = false; for (int dstEdge : dstEdges) { int sign = 1; if (matchEdgePairTranslation(mesh, srcEdge, dstEdge, dis, tol, sign)) { pairedSrc.push_back(srcEdge); pairedDst.push_back(dstEdge); pairedSign.push_back(sign); matched = true; break; } } if (!matched) { pairedSrc.push_back(srcEdge); pairedDst.push_back(srcEdge); pairedSign.push_back(1); } } return; } // Order-2: first-match with loose tol, then drop duplicate dst (keep first). // Pure first-match without dedup breaks projection (duplicate dst). std::vector srcU = srcEdges; std::vector dstU = dstEdges; std::sort(srcU.begin(), srcU.end()); srcU.erase(std::unique(srcU.begin(), srcU.end()), srcU.end()); std::sort(dstU.begin(), dstU.end()); dstU.erase(std::unique(dstU.begin(), dstU.end()), dstU.end()); std::vector dstUsed(static_cast(dstU.size()), 0); for (int srcEdge : srcU) { bool matched = false; for (size_t dj = 0; dj < dstU.size(); dj++) { if (dstUsed[dj]) continue; int sign = 1; if (!matchEdgePairTranslation(mesh, srcEdge, dstU[dj], dis, tol, sign)) continue; pairedSrc.push_back(srcEdge); pairedDst.push_back(dstU[dj]); pairedSign.push_back(sign); dstUsed[dj] = 1; matched = true; break; } if (!matched) { pairedSrc.push_back(srcEdge); pairedDst.push_back(srcEdge); pairedSign.push_back(1); } } return; } void pairEdgesByGeometry(Mesh_3D* mesh, const std::vector& srcEdges, const std::vector& dstEdges, double theta, std::vector& pairedSrc, std::vector& pairedDst, std::vector& pairedSign) { // MATLAB rotation PBC: err = 0.01*5e-5, first match, no dst lock. const double tol = 0.01 * 0.00005; for (int srcEdge : srcEdges) { bool matched = false; for (int dstEdge : dstEdges) { int sign = 1; if (matchEdgePair(mesh, srcEdge, dstEdge, theta, tol, sign)) { pairedSrc.push_back(srcEdge); pairedDst.push_back(dstEdge); pairedSign.push_back(sign); matched = true; break; } } if (!matched) { pairedSrc.push_back(srcEdge); pairedDst.push_back(srcEdge); pairedSign.push_back(1); } } } void getFaceCentroid(Mesh_3D* mesh, int faceId, Eigen::Vector3d& centroid) { Eigen::Vector3d v0, v1, v2; mesh->GetVertex(mesh->GetFace(faceId, 0), v0); mesh->GetVertex(mesh->GetFace(faceId, 1), v1); mesh->GetVertex(mesh->GetFace(faceId, 2), v2); centroid = (v0 + v1 + v2) / 3.0; } void collectFacesOnDomains(Mesh_3D* mesh, const Eigen::VectorXi& domains, std::vector& faces) { // Mirror MATLAB findTri: gather tris on all domains, sort, then FaceOfTet. std::vector triIndex; for (int d = 0; d < domains.size(); d++) { const int domainId = domains(d); for (int j = 0; j < mesh->GetNbrTri(); j++) { if (mesh->GetDomainOfTri(j) == domainId) triIndex.push_back(j); } } std::sort(triIndex.begin(), triIndex.end()); faces.clear(); faces.reserve(triIndex.size()); for (int j : triIndex) { Eigen::Vector3i conn; mesh->GetCoonOfTri(j, conn); faces.push_back(mesh->GetFaceOfTet(conn(0), conn(1))); } } bool matchFacePair(Mesh_3D* mesh, int srcFace, int dstFace, double theta, double tol) { // MATLAB order2 face branch (rotation): ‖c_src − R·c_dst‖ < err, sign = +1. Eigen::Vector3d c1, c2; getFaceCentroid(mesh, srcFace, c1); getFaceCentroid(mesh, dstFace, c2); Eigen::Matrix3d traMat; traMat << std::cos(theta), -std::sin(theta), 0.0, std::sin(theta), std::cos(theta), 0.0, 0.0, 0.0, 1.0; c2 = traMat * c2; return (c1 - c2).norm() < tol; } bool matchFacePairTranslation(Mesh_3D* mesh, int srcFace, int dstFace, const Eigen::Vector3d& dis, double tol) { // Translation port of MATLAB face branch: transform dst by −dis (src+dis=dst). Eigen::Vector3d c1, c2; getFaceCentroid(mesh, srcFace, c1); getFaceCentroid(mesh, dstFace, c2); return (c1 - (c2 - dis)).norm() < tol; } void pairFacesByTranslation(Mesh_3D* mesh, const std::vector& srcFaces, const std::vector& dstFaces, const Eigen::Vector3d& dis, std::vector& pairedSrc, std::vector& pairedDst, std::vector& pairedSign) { // Face branch of MATLAB findPBCIndex (translation form of ‖c_src−T(c_dst)‖). // MATLAB uses first-match without dst-lock; that yields duplicate dst rows and // breaks buildPeriodicProjection* (assumes unique sorted dst). We unique face // ids, then assign globally best residual first with exclusive dst — same // geometric criterion, projection-safe. std::vector srcU = srcFaces; std::vector dstU = dstFaces; std::sort(srcU.begin(), srcU.end()); srcU.erase(std::unique(srcU.begin(), srcU.end()), srcU.end()); std::sort(dstU.begin(), dstU.end()); dstU.erase(std::unique(dstU.begin(), dstU.end()), dstU.end()); const double tol = matlabFacePbcTol(dis); const int nSrc = static_cast(srcU.size()); const int nDst = static_cast(dstU.size()); struct Cand { double err; int si; int di; }; std::vector cands; cands.reserve(static_cast(nSrc)); for (int si = 0; si < nSrc; si++) { Eigen::Vector3d c1; getFaceCentroid(mesh, srcU[static_cast(si)], c1); for (int di = 0; di < nDst; di++) { Eigen::Vector3d c2; getFaceCentroid(mesh, dstU[static_cast(di)], c2); const double err = (c1 - (c2 - dis)).norm(); if (err < tol) cands.push_back({ err, si, di }); } } std::sort(cands.begin(), cands.end(), [](const Cand& a, const Cand& b) { return a.err < b.err; }); std::vector matchDst(static_cast(nSrc), -1); std::vector srcUsed(static_cast(nSrc), 0); std::vector dstUsed(static_cast(nDst), 0); for (const Cand& c : cands) { if (srcUsed[static_cast(c.si)] || dstUsed[static_cast(c.di)]) continue; srcUsed[static_cast(c.si)] = 1; dstUsed[static_cast(c.di)] = 1; matchDst[static_cast(c.si)] = c.di; } for (int si = 0; si < nSrc; si++) { pairedSrc.push_back(srcU[static_cast(si)]); if (matchDst[static_cast(si)] >= 0) pairedDst.push_back(dstU[static_cast(matchDst[static_cast(si)])]); else pairedDst.push_back(srcU[static_cast(si)]); pairedSign.push_back(1); } } void pairFacesByGeometry(Mesh_3D* mesh, const std::vector& srcFaces, const std::vector& dstFaces, double theta, std::vector& pairedSrc, std::vector& pairedDst, std::vector& pairedSign) { const double tol = 0.01 * 0.00005; for (int srcFace : srcFaces) { bool matched = false; for (int dstFace : dstFaces) { if (matchFacePair(mesh, srcFace, dstFace, theta, tol)) { pairedSrc.push_back(srcFace); pairedDst.push_back(dstFace); pairedSign.push_back(1); matched = true; break; } } if (!matched) { pairedSrc.push_back(srcFace); pairedDst.push_back(srcFace); pairedSign.push_back(1); } } } void removeSelfPairs(std::vector& srcEdges, std::vector& dstEdges, std::vector>& phis) { std::vector newSrc, newDst; std::vector> newPhi; for (size_t i = 0; i < srcEdges.size(); i++) { if (srcEdges[i] == dstEdges[i]) continue; newSrc.push_back(srcEdges[i]); newDst.push_back(dstEdges[i]); newPhi.push_back(phis[i]); } srcEdges.swap(newSrc); dstEdges.swap(newDst); phis.swap(newPhi); } } // namespace void Mesh_2D::GetIndexOfPBC(Eigen::MatrixXi PBC, Eigen::VectorXcd PBCData, Eigen::VectorXi& srcNodeIndex, Eigen::VectorXi& dstNodeIndex, Eigen::VectorXcd& nodePhi, Eigen::VectorXi& srcEdgeIndex, Eigen::VectorXi& dstEdgeIndex, Eigen::VectorXcd& edgePhi) { int NbrEdges = 0; int NbrDomain = PBC.rows(); for (int i = 0; i < NbrDomain; i++) { for (int j = 0; j < _mNbrEdges; j++) { if (GetDomainOfEdges(j)-1 == PBC(i, 0)) NbrEdges++; } } //store srcEdgeIndex and srcNodeIndex Eigen::Vector2i coonOfEdges; int* tempSrcEdgeIndex, * tempSrcNodeIndex; tempSrcEdgeIndex = new int[NbrEdges]; tempSrcNodeIndex = new int[NbrEdges * 2]; std::complex* tempEdgePhi, * tempNodePhi; tempEdgePhi = new std::complex[NbrEdges]; tempNodePhi = new std::complex[NbrEdges * 2]; int numNode = 0; int numEdge = 0; int Tage_numEdge = 0; for (int i = 0; i < NbrDomain; i++) { for (int j = 0; j < _mNbrEdges; j++) { if (GetDomainOfEdges(j) - 1 == PBC(i, 0)) { tempSrcEdgeIndex[numEdge] = j; tempEdgePhi[numEdge] = PBCData(i); numEdge++; this->GetCoonOfEdges(j, coonOfEdges); Tage_numEdge = GetEdgeOfTri(coonOfEdges(0), coonOfEdges(1)); tempSrcNodeIndex[numNode] = GetEdge(Tage_numEdge, 0); tempNodePhi[numNode] = PBCData(i); numNode++; tempSrcNodeIndex[numNode] = GetEdge(Tage_numEdge, 1); tempNodePhi[numNode] = PBCData(i); numNode++; } } } //store dstEdgeIndex and dstNodeIndex int* tempDstEdgeIndex, * tempDstNodeIndex; tempDstEdgeIndex = new int[NbrEdges]; tempDstNodeIndex = new int[NbrEdges * 2]; for (int i = 0; i < NbrEdges; i++) { for (int j = 0; j < _mCopyOfEdges.rows(); j++) { if (tempSrcEdgeIndex[i] == _mCopyOfEdges(j, 0)) { tempDstEdgeIndex[i] = _mCopyOfEdges(j, 1); break; } } } for (int i = 0; i < NbrEdges; i++) { this->GetCoonOfEdges(tempDstEdgeIndex[i], coonOfEdges); Tage_numEdge = GetEdgeOfTri(coonOfEdges(0), coonOfEdges(1)); tempDstNodeIndex[i * 2] = GetEdge(Tage_numEdge, 0); tempDstNodeIndex[i * 2 + 1] = GetEdge(Tage_numEdge, 1); } //????????? DstNodeIndex ?? edgePhi //??????rotational bloch bounadry for (int i = 0; i < NbrEdges; i++) { for (int j = 0; j < _mCopyOfVertex.rows(); j++) { if (tempSrcNodeIndex[2 * i] == _mCopyOfVertex(j, 0) && tempDstNodeIndex[2 * i + 1] == _mCopyOfVertex(j, 1)) { int temp = tempDstNodeIndex[i * 2]; tempDstNodeIndex[i * 2] = tempDstNodeIndex[i * 2 + 1]; tempDstNodeIndex[i * 2 + 1] = temp; tempEdgePhi[i] = - tempEdgePhi[i]; } } } srcEdgeIndex = Eigen::VectorXi::Zero(NbrEdges); dstEdgeIndex = Eigen::VectorXi::Zero(NbrEdges); edgePhi = Eigen::VectorXcd::Zero(NbrEdges); for (int i = 0; i < NbrEdges; i++) { this->GetCoonOfEdges(tempSrcEdgeIndex[i], coonOfEdges); Tage_numEdge = GetEdgeOfTri(coonOfEdges(0), coonOfEdges(1)); srcEdgeIndex(i) = Tage_numEdge; this->GetCoonOfEdges(tempDstEdgeIndex[i], coonOfEdges); Tage_numEdge = GetEdgeOfTri(coonOfEdges(0), coonOfEdges(1)); dstEdgeIndex(i) = Tage_numEdge; edgePhi(i) = tempEdgePhi[i]; } //??????? Eigen::VectorXi overlapIndex1, overlapIndex2; overlapIndex1 = Eigen::VectorXi::Zero(NbrEdges * 2); overlapIndex2 = Eigen::VectorXi::Zero(NbrEdges * 2); int Nbr_overlap; Nbr_overlap = 0; for (int i = 0; i < NbrEdges * 2; i++) { for (int j = i + 1; j < NbrEdges * 2; j++) { if (tempSrcNodeIndex[i] == tempSrcNodeIndex[j]) { if (tempDstNodeIndex[i] == tempDstNodeIndex[j]) { overlapIndex1[Nbr_overlap] = i; overlapIndex2[Nbr_overlap] = j; Nbr_overlap = Nbr_overlap + 1; break; } } } } overlapIndex2.conservativeResize(Nbr_overlap); int tempNum = 0; srcNodeIndex = Eigen::VectorXi::Zero(NbrEdges * 2 - Nbr_overlap); dstNodeIndex = Eigen::VectorXi::Zero(NbrEdges * 2 - Nbr_overlap); nodePhi = Eigen::VectorXcd::Zero(NbrEdges * 2 - Nbr_overlap); for (int i = 0; i < NbrEdges * 2; i++) { if ((overlapIndex2.array() == i).any()) { tempNum++; continue; } srcNodeIndex(i - tempNum) = tempSrcNodeIndex[i]; dstNodeIndex(i - tempNum) = tempDstNodeIndex[i]; nodePhi(i - tempNum) = tempNodePhi[i]; } srcNodeIndex.conservativeResize(NbrEdges * 2 - Nbr_overlap); dstNodeIndex.conservativeResize(NbrEdges * 2 - Nbr_overlap); int blochIndex, blochtemp = -1; for (int i = 0; i < NbrEdges * 2 - Nbr_overlap; i++) { for (int j = i + 1; j < NbrEdges * 2 - Nbr_overlap; j++) { if (srcNodeIndex(i) == srcNodeIndex(j)) { blochtemp = srcNodeIndex[i]; } } } for (int i = 0; i < NbrEdges * 2 - Nbr_overlap; i++) { for (int j = i + 1; j < NbrEdges * 2 - Nbr_overlap; j++) { if (dstNodeIndex(i) == dstNodeIndex(j)) { srcNodeIndex(i) = blochtemp; nodePhi(i) = nodePhi(i) * nodePhi(j); if (j != srcNodeIndex.size() - 1) { srcNodeIndex.segment(j, NbrEdges * 2 - Nbr_overlap - j - 1) = srcNodeIndex.segment(j + 1, NbrEdges * 2 - Nbr_overlap - j - 1); dstNodeIndex.segment(j, NbrEdges * 2 - Nbr_overlap - j - 1) = dstNodeIndex.segment(j + 1, NbrEdges * 2 - Nbr_overlap - j - 1); } } } } if (blochtemp != -1) { srcNodeIndex.conservativeResize(NbrEdges * 2 - Nbr_overlap - 1); dstNodeIndex.conservativeResize(NbrEdges * 2 - Nbr_overlap - 1); } delete[] tempSrcEdgeIndex, tempSrcNodeIndex, tempEdgePhi, tempNodePhi, tempDstEdgeIndex, tempDstNodeIndex; } void Mesh_2D::GetEdgesIndexOfDomain(int domain, Eigen::VectorXi& edgesIndex) { int NbrEdgesIndex = 0; for (int j = 0; j < _mNbrEdges; j++) { if (GetDomainOfEdges(j) == domain) NbrEdgesIndex++; } edgesIndex = Eigen::VectorXi::Zero(NbrEdgesIndex); int NumEdgesIndex = 0; for (int j = 0; j < _mNbrEdges; j++) { if (GetDomainOfEdges(j) == domain) { edgesIndex(NumEdgesIndex) = j; NumEdgesIndex++; } } } void Mesh_3D::GetTriIndexOfDomain(Eigen::VectorXi domain, Eigen::VectorXi& edgeIndex) { int NbrTri = 0; int NbrDomain = domain.rows(); for (int i = 0; i < NbrDomain; i++) { for (int j = 0; j < _mNbrTri; j++) { if (GetDomainOfTri(j) == domain(i)) NbrTri++; } } //store edgeIndex Eigen::Vector3i coonOfTri; int* tempEdgeIndex; tempEdgeIndex = new int[NbrTri * 3]; int numTri = 0; for (int i = 0; i < NbrDomain; i++) { for (int j = 0; j < _mNbrTri; j++) { if (GetDomainOfTri(j) == domain(i)) { Eigen::Vector3i connOfTri; this->GetCoonOfTri(j, connOfTri); if (connOfTri(0) == 0) { if (connOfTri(2) == 0) { tempEdgeIndex[numTri * 3] = this->GetEdgeOfTet(connOfTri(1), 0); tempEdgeIndex[numTri * 3 + 1] = this->GetEdgeOfTet(connOfTri(1), 1); tempEdgeIndex[numTri * 3 + 2] = this->GetEdgeOfTet(connOfTri(1), 2); } else if (connOfTri(2) == 1) { tempEdgeIndex[numTri * 3] = this->GetEdgeOfTet(connOfTri(1), 0); tempEdgeIndex[numTri * 3 + 1] = this->GetEdgeOfTet(connOfTri(1), 2); tempEdgeIndex[numTri * 3 + 2] = this->GetEdgeOfTet(connOfTri(1), 4); } else if (connOfTri(2) == 2) { tempEdgeIndex[numTri * 3] = this->GetEdgeOfTet(connOfTri(1), 1); tempEdgeIndex[numTri * 3 + 1] = this->GetEdgeOfTet(connOfTri(1), 2); tempEdgeIndex[numTri * 3 + 2] = this->GetEdgeOfTet(connOfTri(1), 5); } else if (connOfTri(2) == 3) { tempEdgeIndex[numTri * 3] = this->GetEdgeOfTet(connOfTri(1), 3); tempEdgeIndex[numTri * 3 + 1] = this->GetEdgeOfTet(connOfTri(1), 4); tempEdgeIndex[numTri * 3 + 2] = this->GetEdgeOfTet(connOfTri(1), 5); } } else { } } } } //sort and unique nodeIndex std::sort(tempEdgeIndex, tempEdgeIndex + NbrTri * 3); int NbrEdge = (std::unique(tempEdgeIndex, tempEdgeIndex + NbrTri * 3) - tempEdgeIndex); edgeIndex = Eigen::VectorXi::Zero(NbrEdge); for (int i = 0; i < NbrEdge; i++) edgeIndex(i) = tempEdgeIndex[i]; delete[] tempEdgeIndex; } void Mesh_3D::GetTriIndexOfDomain2(Eigen::VectorXi domain, Eigen::VectorXi indexNum, Eigen::VectorXi& triIndex, Eigen::VectorXi& triNum) { int NbrTri = 0; int NbrDomain = domain.rows(); for (int i = 0; i < NbrDomain; i++) { for (int j = 0; j < _mNbrTri; j++) { if (GetDomainOfTri(j) == domain(i)) NbrTri++; } } //store triIndex triIndex = Eigen::VectorXi::Zero(NbrTri); triNum = Eigen::VectorXi::Zero(NbrTri); int numTri = 0; for (int i = 0; i < NbrDomain; i++) { for (int j = 0; j < NbrTri; j++) { if (GetDomainOfTri(j) == domain(i)) { triIndex(numTri) = j; triNum(numTri) = i; numTri++; } } } } void Mesh_3D::GetIndexOfPBC(Eigen::MatrixXi PBC, Eigen::VectorXcd PBCData, Eigen::VectorXi& srcEdgeIndex, Eigen::VectorXi& dstEdgeIndex, Eigen::VectorXcd& edgePhi) { std::vector srcDomains(PBC.rows()); std::vector dstDomains(PBC.rows()); Eigen::VectorXd angles = Eigen::VectorXd::Zero(PBC.rows()); Eigen::MatrixXd waveVecs = Eigen::MatrixXd::Zero(3, PBC.rows()); for (int i = 0; i < PBC.rows(); i++) { srcDomains[i] = Eigen::VectorXi(1); dstDomains[i] = Eigen::VectorXi(1); srcDomains[i](0) = PBC(i, 0); dstDomains[i](0) = PBC(i, 1); } GetIndexOfPBC(srcDomains, dstDomains, PBCData, angles, waveVecs, srcEdgeIndex, dstEdgeIndex, edgePhi); } void Mesh_3D::GetIndexOfPBC(const std::vector& srcDomains, const std::vector& dstDomains, const Eigen::VectorXcd& PBCData, const Eigen::VectorXd& pbcAngles, const Eigen::MatrixXd& pbcWaveVecs, Eigen::VectorXi& srcEdgeIndex, Eigen::VectorXi& dstEdgeIndex, Eigen::VectorXcd& edgePhi, bool useFaceStyleEdgeTol) { std::vector allSrc, allDst; std::vector> allPhi; for (int pair = 0; pair < static_cast(srcDomains.size()); pair++) { std::vector srcEdges, dstEdges; collectEdgesOnDomains(this, srcDomains[pair], srcEdges); collectEdgesOnDomains(this, dstDomains[pair], dstEdges); const double theta = (pair < pbcAngles.size()) ? pbcAngles(pair) : 0.0; const std::complex blochPhi = (pair < PBCData.size()) ? PBCData(pair) : 1.0; Eigen::Vector3d waveVec = Eigen::Vector3d::Zero(); if (pair < pbcWaveVecs.cols()) waveVec = pbcWaveVecs.col(pair); if (_mNbrCopyOfTri > 0) { for (int i = 0; i < _mNbrCopyOfTri; i++) { allSrc.push_back(_mCopyOfTri(i, 0)); allDst.push_back(_mCopyOfTri(i, 1)); allPhi.push_back(blochPhi); } continue; } std::vector pairedSrc, pairedDst, pairedSign; if (waveVec.norm() >= 1e-30) pairEdgesByTranslation(this, srcEdges, dstEdges, waveVec, pairedSrc, pairedDst, pairedSign, useFaceStyleEdgeTol); else pairEdgesByGeometry(this, srcEdges, dstEdges, theta, pairedSrc, pairedDst, pairedSign); for (size_t i = 0; i < pairedSrc.size(); i++) { allSrc.push_back(pairedSrc[i]); allDst.push_back(pairedDst[i]); allPhi.push_back(blochPhi * static_cast(pairedSign[i])); } } removeSelfPairs(allSrc, allDst, allPhi); const int n = static_cast(allSrc.size()); srcEdgeIndex = Eigen::VectorXi(n); dstEdgeIndex = Eigen::VectorXi(n); edgePhi = Eigen::VectorXcd(n); for (int i = 0; i < n; i++) { srcEdgeIndex(i) = allSrc[i]; dstEdgeIndex(i) = allDst[i]; edgePhi(i) = allPhi[i]; } if (n == 0) return; Eigen::VectorXi tempIndex = Eigen::VectorXi::LinSpaced(n, 0, n - 1); QuickSort(dstEdgeIndex, tempIndex, 0, n - 1); Unique(dstEdgeIndex, tempIndex); Eigen::VectorXcd tempPhi = Eigen::VectorXcd::Zero(dstEdgeIndex.size()); Eigen::VectorXi tempSrc = Eigen::VectorXi::Zero(dstEdgeIndex.size()); for (int i = 0; i < dstEdgeIndex.size(); i++) { tempPhi(i) = edgePhi(tempIndex(i)); tempSrc(i) = srcEdgeIndex(tempIndex(i)); } edgePhi = tempPhi; srcEdgeIndex = tempSrc; } void Mesh_3D::GetIndexOfPBCFaces(const std::vector& srcDomains, const std::vector& dstDomains, const Eigen::VectorXd& pbcAngles, const Eigen::MatrixXd& pbcWaveVecs, Eigen::VectorXi& srcFaceIndex, Eigen::VectorXi& dstFaceIndex, Eigen::VectorXcd& facePhi) { std::vector allSrc, allDst; std::vector> allPhi; for (int pair = 0; pair < static_cast(srcDomains.size()); pair++) { // MATLAB findPBCIndex(src,dst,...): all src domains together, all dst together. std::vector srcFaces, dstFaces; collectFacesOnDomains(this, srcDomains[pair], srcFaces); collectFacesOnDomains(this, dstDomains[pair], dstFaces); const double theta = (pair < pbcAngles.size()) ? pbcAngles(pair) : 0.0; Eigen::Vector3d waveVec = Eigen::Vector3d::Zero(); if (pair < pbcWaveVecs.cols()) waveVec = pbcWaveVecs.col(pair); std::vector pairedSrc, pairedDst, pairedSign; if (waveVec.norm() >= 1e-30) pairFacesByTranslation(this, srcFaces, dstFaces, waveVec, pairedSrc, pairedDst, pairedSign); else pairFacesByGeometry(this, srcFaces, dstFaces, theta, pairedSrc, pairedDst, pairedSign); for (size_t i = 0; i < pairedSrc.size(); i++) { allSrc.push_back(pairedSrc[i]); allDst.push_back(pairedDst[i]); allPhi.push_back(static_cast(pairedSign[i])); } } removeSelfPairs(allSrc, allDst, allPhi); const int n = static_cast(allSrc.size()); srcFaceIndex = Eigen::VectorXi(n); dstFaceIndex = Eigen::VectorXi(n); facePhi = Eigen::VectorXcd(n); for (int i = 0; i < n; i++) { srcFaceIndex(i) = allSrc[i]; dstFaceIndex(i) = allDst[i]; facePhi(i) = allPhi[i]; } if (n == 0) return; Eigen::VectorXi tempIndex = Eigen::VectorXi::LinSpaced(n, 0, n - 1); QuickSort(dstFaceIndex, tempIndex, 0, n - 1); Unique(dstFaceIndex, tempIndex); Eigen::VectorXcd tempPhi = Eigen::VectorXcd::Zero(dstFaceIndex.size()); Eigen::VectorXi tempSrc = Eigen::VectorXi::Zero(dstFaceIndex.size()); for (int i = 0; i < dstFaceIndex.size(); i++) { tempPhi(i) = facePhi(tempIndex(i)); tempSrc(i) = srcFaceIndex(tempIndex(i)); } facePhi = tempPhi; srcFaceIndex = tempSrc; } // Match MATLAB getMesh.m: unique face rows in column-major order (face slot, then tet). void Mesh_3D::BuildFaceTopology() { if (_mNbrTet <= 0) { _mNbrFace = 0; return; } static const int kFaceVert[4][3] = { {0, 1, 2}, {0, 1, 3}, {0, 2, 3}, {1, 2, 3} }; std::vector> faces; faces.reserve(static_cast(_mNbrTet) * 4); _mFaceOfTet = Eigen::MatrixXi::Zero(_mNbrTet, 4); auto findFace = [&](const std::array& key) -> int { for (int i = 0; i < static_cast(faces.size()); i++) { if (faces[static_cast(i)] == key) return i; } return -1; }; for (int f = 0; f < 4; f++) { for (int t = 0; t < _mNbrTet; t++) { std::array key = { _mTet(t, kFaceVert[f][0]), _mTet(t, kFaceVert[f][1]), _mTet(t, kFaceVert[f][2]) }; int fid = findFace(key); if (fid < 0) { fid = static_cast(faces.size()); faces.push_back(key); } _mFaceOfTet(t, f) = fid; } } _mNbrFace = static_cast(faces.size()); _mFace = Eigen::MatrixXi(_mNbrFace, 3); for (int i = 0; i < _mNbrFace; i++) { _mFace(i, 0) = faces[static_cast(i)][0]; _mFace(i, 1) = faces[static_cast(i)][1]; _mFace(i, 2) = faces[static_cast(i)][2]; } }