XIAN-FEM-2026June/3D opticsfem-master/mesh/Mesh_Find.cpp

1047 lines
29 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include"Mesh_Base.h"
#include"../common/util.h"
#include<algorithm>
#include<array>
#include<complex>
#include<iostream>
#include<cmath>
#include<vector>
//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<int>& 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<int>& edges)
{
// Mirror MATLAB findTri + edge collect: gather/sort tris, then unique edges.
std::vector<int> 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=|‖v1v3‖dl|, l2=|‖v2v4‖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<int>& srcEdges,
const std::vector<int>& dstEdges,
const Eigen::Vector3d& dis,
std::vector<int>& pairedSrc,
std::vector<int>& pairedDst,
std::vector<int>& 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<int> srcU = srcEdges;
std::vector<int> 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<char> dstUsed(static_cast<size_t>(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<int>& srcEdges,
const std::vector<int>& dstEdges,
double theta,
std::vector<int>& pairedSrc,
std::vector<int>& pairedDst,
std::vector<int>& 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<int>& faces)
{
// Mirror MATLAB findTri: gather tris on all domains, sort, then FaceOfTet.
std::vector<int> 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<int>& srcFaces,
const std::vector<int>& dstFaces,
const Eigen::Vector3d& dis,
std::vector<int>& pairedSrc,
std::vector<int>& pairedDst,
std::vector<int>& pairedSign)
{
// Face branch of MATLAB findPBCIndex (translation form of ‖c_srcT(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<int> srcU = srcFaces;
std::vector<int> 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<int>(srcU.size());
const int nDst = static_cast<int>(dstU.size());
struct Cand { double err; int si; int di; };
std::vector<Cand> cands;
cands.reserve(static_cast<size_t>(nSrc));
for (int si = 0; si < nSrc; si++)
{
Eigen::Vector3d c1;
getFaceCentroid(mesh, srcU[static_cast<size_t>(si)], c1);
for (int di = 0; di < nDst; di++)
{
Eigen::Vector3d c2;
getFaceCentroid(mesh, dstU[static_cast<size_t>(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<int> matchDst(static_cast<size_t>(nSrc), -1);
std::vector<char> srcUsed(static_cast<size_t>(nSrc), 0);
std::vector<char> dstUsed(static_cast<size_t>(nDst), 0);
for (const Cand& c : cands)
{
if (srcUsed[static_cast<size_t>(c.si)] || dstUsed[static_cast<size_t>(c.di)])
continue;
srcUsed[static_cast<size_t>(c.si)] = 1;
dstUsed[static_cast<size_t>(c.di)] = 1;
matchDst[static_cast<size_t>(c.si)] = c.di;
}
for (int si = 0; si < nSrc; si++)
{
pairedSrc.push_back(srcU[static_cast<size_t>(si)]);
if (matchDst[static_cast<size_t>(si)] >= 0)
pairedDst.push_back(dstU[static_cast<size_t>(matchDst[static_cast<size_t>(si)])]);
else
pairedDst.push_back(srcU[static_cast<size_t>(si)]);
pairedSign.push_back(1);
}
}
void pairFacesByGeometry(Mesh_3D* mesh,
const std::vector<int>& srcFaces,
const std::vector<int>& dstFaces,
double theta,
std::vector<int>& pairedSrc,
std::vector<int>& pairedDst,
std::vector<int>& 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<int>& srcEdges,
std::vector<int>& dstEdges,
std::vector<std::complex<double>>& phis)
{
std::vector<int> newSrc, newDst;
std::vector<std::complex<double>> 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<double>* tempEdgePhi, * tempNodePhi;
tempEdgePhi = new std::complex<double>[NbrEdges];
tempNodePhi = new std::complex<double>[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<Eigen::VectorXi> srcDomains(PBC.rows());
std::vector<Eigen::VectorXi> 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<Eigen::VectorXi>& srcDomains,
const std::vector<Eigen::VectorXi>& 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<int> allSrc, allDst;
std::vector<std::complex<double>> allPhi;
for (int pair = 0; pair < static_cast<int>(srcDomains.size()); pair++)
{
std::vector<int> 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<double> 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<int> 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<double>(pairedSign[i]));
}
}
removeSelfPairs(allSrc, allDst, allPhi);
const int n = static_cast<int>(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<Eigen::VectorXi>& srcDomains,
const std::vector<Eigen::VectorXi>& dstDomains,
const Eigen::VectorXd& pbcAngles,
const Eigen::MatrixXd& pbcWaveVecs,
Eigen::VectorXi& srcFaceIndex, Eigen::VectorXi& dstFaceIndex, Eigen::VectorXcd& facePhi)
{
std::vector<int> allSrc, allDst;
std::vector<std::complex<double>> allPhi;
for (int pair = 0; pair < static_cast<int>(srcDomains.size()); pair++)
{
// MATLAB findPBCIndex(src,dst,...): all src domains together, all dst together.
std::vector<int> 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<int> 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<double>(pairedSign[i]));
}
}
removeSelfPairs(allSrc, allDst, allPhi);
const int n = static_cast<int>(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<std::array<int, 3>> faces;
faces.reserve(static_cast<size_t>(_mNbrTet) * 4);
_mFaceOfTet = Eigen::MatrixXi::Zero(_mNbrTet, 4);
auto findFace = [&](const std::array<int, 3>& key) -> int {
for (int i = 0; i < static_cast<int>(faces.size()); i++)
{
if (faces[static_cast<size_t>(i)] == key)
return i;
}
return -1;
};
for (int f = 0; f < 4; f++)
{
for (int t = 0; t < _mNbrTet; t++)
{
std::array<int, 3> 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<int>(faces.size());
faces.push_back(key);
}
_mFaceOfTet(t, f) = fid;
}
}
_mNbrFace = static_cast<int>(faces.size());
_mFace = Eigen::MatrixXi(_mNbrFace, 3);
for (int i = 0; i < _mNbrFace; i++)
{
_mFace(i, 0) = faces[static_cast<size_t>(i)][0];
_mFace(i, 1) = faces[static_cast<size_t>(i)][1];
_mFace(i, 2) = faces[static_cast<size_t>(i)][2];
}
}