Loading files
This file is pinned to the selected release. Download the original to open it in your design tool.
#include"QMeshNode.h"
#include"QMeshFace.h"
#include"QMeshTetra.h"
#include"QMeshEdge.h"
#include"QMeshPatch.h"
#include<iostream>
#include"heatMethod.h"
heatMethod::heatMethod(QMeshPatch* MatSp) {
materialSpace = MatSp;
_initialiseMesh();
}
void heatMethod::_initialiseMesh() {
QMeshPatch* patch = materialSpace;
bool is_TetMesh = true;
//----initial the edge, node and face index, start from 0
int index = 0;
for (GLKPOSITION Pos = patch->GetEdgeList().GetHeadPosition(); Pos;) {
QMeshEdge* Edge = (QMeshEdge*)patch->GetEdgeList().GetNext(Pos);
Edge->FieldIndexNumber = index;
index++;
}
index = 0;
for (GLKPOSITION Pos = patch->GetFaceList().GetHeadPosition(); Pos;) {
QMeshFace* Face = (QMeshFace*)patch->GetFaceList().GetNext(Pos);
Face->FieldIndexNumber = index;
Face->CalPlaneEquation(); // pre-compute the normal of face
index++;
}
index = 0;
for (GLKPOSITION Pos = patch->GetNodeList().GetHeadPosition(); Pos;) {
QMeshNode* Node = (QMeshNode*)patch->GetNodeList().GetNext(Pos);
Node->FieldIndexNumber = index;
index++;
}
// only tet mesh needs reorder the index of Tetra
if (is_TetMesh) {
index = 0;
for (GLKPOSITION Pos = patch->GetTetraList().GetHeadPosition(); Pos;) {
QMeshTetra* Tetra = (QMeshTetra*)patch->GetTetraList().GetNext(Pos);
Tetra->FieldIndexNumber = index;
index++;
}
}
}
void heatMethod::generateHeatField(int BoundCon) {
_createWeightMatrix();
_solveHeatField(BoundCon);
}
void heatMethod::_createWeightMatrix() {
std::cout << "Creating Weight Matrix\n";
int num = materialSpace->GetNodeNumber();
int num_nodes = num - Num_nodesInConvexHull;
std::cout << num_nodes << std::endl;
WeightMatrix.resize(num_nodes, num_nodes);
VolumeMatrix.resize(num_nodes, num_nodes);
VolumeMatrix.reserve(Eigen::VectorXi::Constant(num_nodes, 2));
WeightMatrix.reserve(Eigen::VectorXi::Constant(num_nodes, 35));
Eigen::MatrixXd VolumeMatrix_temp = Eigen::MatrixXd(num_nodes, num_nodes);
int ccount = 0;
for (GLKPOSITION tetPos = materialSpace->GetTetraList().GetHeadPosition(); tetPos;) {
QMeshTetra* tet = (QMeshTetra*)materialSpace->GetTetraList().GetNext(tetPos);
for (int n = 0; n < 6; n++) {
QMeshEdge* edge = tet->GetEdgeRecordPtr(n + 1);
int i = edge->GetStartPoint()->FieldIndexNumber;
int j = edge->GetEndPoint()->FieldIndexNumber;
if (i == -1 || j == -1) {
std::cerr << "Node inside CH encountered while computing weight!!\n";
}
QMeshNode* node_i = edge->GetStartPoint();
QMeshNode* node_j = edge->GetEndPoint();
double _weight = _getEdgeWeight(edge, tet);
if (!edge->visited) {
WeightMatrix.insert(i, j) = _weight;
WeightMatrix.insert(j, i) = WeightMatrix.coeff(i, j);
edge->visited = true;
}
else {
WeightMatrix.coeffRef(i, j) += _weight;
WeightMatrix.coeffRef(j, i) = WeightMatrix.coeff(i, j);
}
if (!node_i->visited_forWeight) {
WeightMatrix.insert(i, i) = -_weight;
node_i->visited_forWeight = true;
}
else {
WeightMatrix.coeffRef(i, i) -= _weight;
}
if (!node_j->visited_forWeight) {
WeightMatrix.insert(j, j) = -_weight;
node_j->visited_forWeight = true;
}
else {
WeightMatrix.coeffRef(j, j) -= _weight;
}
}
tet->CalVolume();
double _vol = tet->GetVolume();
for (int n = 0; n < 4; n++) {
QMeshNode* node = tet->GetNodeRecordPtr(n + 1);
int k = node->FieldIndexNumber;
if (!node->visited_forVol) {
VolumeMatrix.insert(k, k) = (_vol / 4.0);
node->visited_forVol = true;
}
else {
VolumeMatrix.coeffRef(k, k) += (_vol / 4.0);
}
}
}
}
double heatMethod::_getEdgeWeight(QMeshEdge* edge, QMeshTetra* tet) {
QMeshNode* node1 = edge->GetStartPoint();
QMeshNode* node2 = edge->GetEndPoint();
int index1_in_tet = tet->GetNodeIndex(node1);
int index2_in_tet = tet->GetNodeIndex(node2);
QMeshFace* t_face1, * t_face2; //see the defination of discrete Laplacian for tet mesh to understand these faces and the edge
QMeshEdge* t_edge;
QMeshNode* otherNode1, * otherNode2;
bool foundOne = false;
for (int k = 1; k <= 4; k++) {
if (k != index1_in_tet && k != index2_in_tet) {
if (!foundOne) {
otherNode1 = tet->GetNodeRecordPtr(k);
foundOne = true;
}
else {
otherNode2 = tet->GetNodeRecordPtr(k);
}
}
}
if (otherNode1 == NULL || otherNode2 == NULL) {
std::cout << "GOT NULL OTHERNODE!!!!!!\n\n";
}
double x0, y0, z0, x1, y1, z1, x2, y2, z2;
otherNode1->GetCoord3D(x0, y0, z0);
otherNode2->GetCoord3D(x1, y1, z1);
node1->GetCoord3D(x2, y2, z2);
Eigen::Vector3d vfixed(x1 - x0, y1 - y0, z1 - z0);
Eigen::Vector3d v0(x2 - x0, y2 - y0, z2 - z0);
Eigen::Vector3d v1 = vfixed.cross(v0);
node2->GetCoord3D(x2, y2, z2);
Eigen::Vector3d v00(x2 - x0, y2 - y0, z2 - z0);
Eigen::Vector3d v2 = vfixed.cross(v00);
double length = abs(vfixed.norm());
long double _dot = v1.dot(v2) / (v1.norm() * v2.norm());
if (_dot > 1) _dot = 1;
else if (_dot < -1) _dot = -1;
double angle = acos(_dot);
double eps = 0.00001;
if (angle < eps) angle += eps;
double _cotan = cos(angle) / sin(angle);
return (double)length * _cotan / 6.0;
}
void heatMethod::_solveHeatField(int BoundaryCondition) {
int num = materialSpace->GetNodeNumber();
int num_nodes = num - Num_nodesInConvexHull;
this->constNodeNumber = _defineBouindaryNodes();
Eigen::VectorXd u(num_nodes);
Eigen::SparseMatrix<double> S;
Eigen::SparseMatrix<double> I = Eigen::SparseMatrix<double>(num_nodes, num_nodes);
I.setIdentity();
std::cout << "Initialising u...\n";
_initialiseSystemValues2(u, 1.0, 0.0);
Eigen::VectorXd uD(num_nodes);
Eigen::VectorXd uN(num_nodes);
uD.setZero();
uN.setZero();
double t = _getAverageEdgeLength();
t = t * t;
std::cout << "t: " << t << std::endl;
std::cout << "Inversing Volume Matrix...\n";
_inverseVolumeMatrix();
Eigen::SparseMatrix<double> invVol = VolumeMatrix;
Eigen::SparseMatrix<double> test(num_nodes, num_nodes);
test.setIdentity();
double neumann = ((double)BoundaryCondition / 100.0);
double dirichlet = 1.0 - neumann;
if (BoundaryCondition > 0) {
std::cout << "Forcing Boundary Conditions..\n";
for (GLKPOSITION nodePos = materialSpace->GetNodeList().GetHeadPosition(); nodePos;) {
QMeshNode* node = (QMeshNode*)materialSpace->GetNodeList().GetNext(nodePos);
if (node->isSource) {
invVol.coeffRef(node->FieldIndexNumber, node->FieldIndexNumber) = 0.0;
}
else {
test.coeffRef(node->FieldIndexNumber, node->FieldIndexNumber) = 0.0;
}
}
std::cout << "Solving Now..\n";
S = I - 100 * t * invVol * WeightMatrix;
std::cout << "Initialising Sparse Solver..\n";
Eigen::PardisoLU <Eigen::SparseMatrix<double>> SolverN;// (PardisoLU/SparseLU)
SolverN.analyzePattern(S);
SolverN.factorize(S);
if (SolverN.info() != Eigen::Success)
std::cout << "error here: factorize fail!" << std::endl;
SolverN.compute(S);
uN = SolverN.solve(u);
std::cout << "Neuman Soln. Complete..\n";
invVol = VolumeMatrix;
}
//Dirichlet Solution
if (BoundaryCondition < 100) {
std::cout << "Forcing Boundary Conditions..\n";
for (GLKPOSITION nodePos = materialSpace->GetNodeList().GetHeadPosition(); nodePos;) {
QMeshNode* node = (QMeshNode*)materialSpace->GetNodeList().GetNext(nodePos);
if (node->in_ConvexHull) continue;
if (node->isBoundary) {
invVol.coeffRef(node->FieldIndexNumber, node->FieldIndexNumber) = 0.0;
}
else {
test.coeffRef(node->FieldIndexNumber, node->FieldIndexNumber) = 0.0;
}
}
std::cout << "Solving Now..\n";
S = I - 100 * t * invVol * WeightMatrix;
std::cout << "Initialising Sparse Solver..\n";
Eigen::PardisoLU <Eigen::SparseMatrix<double>> Solver;// (PardisoLU/SparseLU)
Solver.analyzePattern(S);
Solver.factorize(S);
if (Solver.info() != Eigen::Success)
std::cout << "error here: factorize fail!" << std::endl;
Solver.compute(S);
std::cout << "Sparse Solver Initialised\n";
uD = Solver.solve(u);
std::cout << "Dirichlet Soln. Complete..\n";
}
std::cout << "System solved for initial field...\n";
double min = 99999, max = -9999;
for (GLKPOSITION pos = materialSpace->GetNodeList().GetHeadPosition(); pos;) {
QMeshNode* node = (QMeshNode*)materialSpace->GetNodeList().GetNext(pos);
if (node->in_ConvexHull) continue;
int i = node->FieldIndexNumber;
u[i] = (neumann * uN[i]) + (dirichlet * uD[i]);
node->HeatFieldValue = u[i];
node->scalarField = u[i];
if (node->HeatFieldValue < min) min = node->HeatFieldValue;
if (node->HeatFieldValue > max) max = node->HeatFieldValue;
}
std::cout << "Max: " << max << "Min: " << min << std::endl;
std::cout << "\n\n\n";
double range = max - min;
}
double heatMethod::_getAverageEdgeLength() {
std::cout << "Getting average edge length...\n";
double length = 0;
double n = materialSpace->GetEdgeNumber();
double count_ = 0;
for (GLKPOSITION pos = materialSpace->GetEdgeList().GetHeadPosition(); pos;) {
QMeshEdge* edge = (QMeshEdge*)materialSpace->GetEdgeList().GetNext(pos);
length += edge->GetLength();
count_++;
}
return length / count_;
}
void heatMethod::_initialiseSystemValues2(Eigen::VectorXd& u, double sourceVal, double otherVal) {
double boundingBox[6];
materialSpace->ComputeBoundingBox(boundingBox);
double minY = boundingBox[2];
double maxY = boundingBox[3];
int num = materialSpace->GetNodeNumber();
int cnum = this->constNodeNumber;
for (GLKPOSITION nodePos = materialSpace->GetNodeList().GetHeadPosition(); nodePos;) {
QMeshNode* node = (QMeshNode*)materialSpace->GetNodeList().GetNext(nodePos);
if (node->in_ConvexHull) continue;
if (node->isBoundary) {
if (node->isSource) {
u[node->FieldIndexNumber] = sourceVal;
}
else u[node->FieldIndexNumber] = otherVal;
}
else {
u[node->FieldIndexNumber] = otherVal;
}
}
}
int heatMethod::_defineBouindaryNodes() {
double boundingBox[6];
materialSpace->ComputeBoundingBox(boundingBox);
double minX = boundingBox[0];
double maxX = boundingBox[1];
double minY = boundingBox[2];
double maxY = boundingBox[3];
double minZ = boundingBox[4];
double maxZ = boundingBox[5];
double Xav = (minX + maxX) * 0.50;
double Yav = (minY + maxY) * 0.50;
double Zav = (minZ + maxZ) * 0.50;
double Xrange = (-minX + maxX) / 4;
double Yrange = (-minY + maxY) / 4;
double Zrange = (-minZ + maxZ) / 4;
int num = materialSpace->GetNodeNumber();
int count = 0;
for (GLKPOSITION nodePos = materialSpace->GetNodeList().GetHeadPosition(); nodePos;) {
QMeshNode* node = (QMeshNode*)materialSpace->GetNodeList().GetNext(nodePos);
if (node->in_ConvexHull) continue;
double xx, yy, zz;
node->GetCoord3D(xx, yy, zz);
if (yy < (minY + 1) /*node->isBoundary*/)
{
node->isBoundary = true;
std::cout << "I am here first\n";
constIndex.push_back(true);
node->isSource = true;
}
//else if (/*yy < (minY + 0.0001)*//*(abs(xx - Xav) < Xrange) && (abs(yy - Yav) < Yrange) && (abs(zz - Zav) < Zrange)*/ node->ConvexHull_boundary) {
// node->isBoundary = true;
// std::cout << "\nI am here\n\n";
// constIndex.push_back(true);
// //node->isTopBoundary = true;
// //node->isSource = true;
//
//}
else {
node->ReducedFieldIndexNumber = count;
node->isBoundary = false;
constIndex.push_back(false);
count++;
}
}
return num - count;
}
void heatMethod::_buildTetLaplacianMatrix()
{
int num = materialSpace->GetTetraNumber();
int num_tets = num - Num_tetInConvexHull;
Eigen::SparseMatrix<double> diagonalMultiplier;
TetLaplacianMatrix.resize(num_tets + num_tets, num_tets);
TetLaplacianMatrix.setZero();
TetLaplacianMatrix.reserve(Eigen::VectorXd::Constant(num_tets + num_tets, 10));
diagonalMultiplier.resize(num_tets + num_tets, num_tets + num_tets);
//diagonalMultiplier.reserve(Eigen::VectorXd::Constant(num_tets + pivotNumber, 2));
diagonalMultiplier.setIdentity();
//TetLaplacianMatrix.setIdentity();
std::cout << "I am here 1\n";
for (GLKPOSITION facePos = materialSpace->GetFaceList().GetHeadPosition(); facePos;) {
QMeshFace* face = (QMeshFace*)materialSpace->GetFaceList().GetNext(facePos);
QMeshTetra* tet1 = face->GetRightTetra();
QMeshTetra* tet2 = face->GetLeftTetra();
if (tet1 == NULL || tet2 == NULL) continue;
//if (tet1->discard || tet2->discard) continue;
int i = tet1->FieldIndexNumber;
int j = tet2->FieldIndexNumber;
TetLaplacianMatrix.insert(i, j) = -1;
TetLaplacianMatrix.insert(j, i) = -1;
if (TetLaplacianMatrix.coeff(i, i) == 0) {
TetLaplacianMatrix.insert(i, i) = 1;
}
else {
TetLaplacianMatrix.coeffRef(i, i)++;
}
if (TetLaplacianMatrix.coeff(j, j) == 0) {
TetLaplacianMatrix.insert(j, j) = 1;
}
else {
TetLaplacianMatrix.coeffRef(j, j)++;
}
}
std::cout << "I am here 2\n";
for (int l = 0; l < num_tets; l++) {
diagonalMultiplier.coeffRef(l, l) = 1 / TetLaplacianMatrix.coeff(l, l);
}
std::cout << "I am here 3\n";
int pivotInsertCount = 0;
for (GLKPOSITION tetPos = materialSpace->GetTetraList().GetHeadPosition(); tetPos;) {
QMeshTetra* tetra = (QMeshTetra*)materialSpace->GetTetraList().GetNext(tetPos);
//if (!tetra->isPivot) continue;
int i = tetra->FieldIndexNumber;
int indexx = pivotInsertCount + num_tets;
//TetLaplacianMatrix.insert(indexx, i) = 0.001;
if (tetra->isPivot) {
if (tetra->isPivotA)
TetLaplacianMatrix.coeffRef(indexx, i) = 9e8;
if (tetra->isPivotB)
TetLaplacianMatrix.coeffRef(indexx, i) = 500e4;
else
TetLaplacianMatrix.coeffRef(indexx, i) = 500e4;
}
pivotInsertCount++;
}
TetLaplacianMatrix = diagonalMultiplier * TetLaplacianMatrix;
}
void heatMethod::_createSolutionVectorForVectorSmoothing(int column, Eigen::VectorXd& u)
{
int num = materialSpace->GetTetraNumber();
int num_tets = num - Num_tetInConvexHull;
std::cout << "Creating vector " << column << std::endl;
int pivotInsertCount = 0;
for (GLKPOSITION tetPos = materialSpace->GetTetraList().GetHeadPosition(); tetPos;) {
QMeshTetra* tetra = (QMeshTetra*)materialSpace->GetTetraList().GetNext(tetPos);
int index = tetra->FieldIndexNumber;
if (column < 3) {
Eigen::Vector3d thisVector(VectorFieldMatrix(index, 0), VectorFieldMatrix(index, 1), VectorFieldMatrix(index, 2));
//double vectorSize = thisVector.stableNorm();
double vectorSize = 1.0;
thisVector.stableNormalize();
//u(num_tets + index) = 0.001 * thisVector(column);
if (true) {
if (tetra->isPivotA)
u(num_tets + pivotInsertCount) = 9e8 * thisVector(column);
if (tetra->isPivotB)
u(num_tets + pivotInsertCount) = 500e4 * thisVector(column);
else
u(num_tets + pivotInsertCount) = 500e4 * thisVector(column);
pivotInsertCount++;
}
}
else {
Eigen::Vector3d thisVector(VectorFieldMatrix(index, 0), VectorFieldMatrix(index, 1), VectorFieldMatrix(index, 2));
double vectorSize = thisVector.stableNorm();
//u(num_tets + index) = 0.001 * vectorSize;
if (tetra->isPivot) {
if (tetra->isPivotA)
u(num_tets + pivotInsertCount) = 800 * vectorSize;
else
u(num_tets + pivotInsertCount) = 200 * vectorSize;
pivotInsertCount++;
}
}
}
}
void heatMethod::_smoothVectorField()
{
int num = materialSpace->GetTetraNumber();
int num_tets = num - Num_tetInConvexHull;
_buildTetLaplacianMatrix();
Eigen::VectorXd v0 = Eigen::VectorXd::Zero(2 * num_tets);
Eigen::VectorXd v1 = Eigen::VectorXd::Zero(2 * num_tets);
Eigen::VectorXd v2 = Eigen::VectorXd::Zero(2 * num_tets);
Eigen::VectorXd v3 = Eigen::VectorXd::Zero(2 * num_tets);
Eigen::VectorXd v0_sol(num_tets);
Eigen::VectorXd v1_sol(num_tets);
Eigen::VectorXd v2_sol(num_tets);
Eigen::VectorXd v3_sol(num_tets);
_createSolutionVectorForVectorSmoothing(0, v0);
_createSolutionVectorForVectorSmoothing(1, v1);
_createSolutionVectorForVectorSmoothing(2, v2);
_createSolutionVectorForVectorSmoothing(3, v3);
std::cout << "Initialising Sparse Solver for vector smoothing..\n";
Eigen::PardisoLU <Eigen::SparseMatrix<double>> SolverN;// (PardisoLU/SparseLU)
Eigen::SparseMatrix<double> S = TetLaplacianMatrix.transpose() * TetLaplacianMatrix;
SolverN.analyzePattern(S);
SolverN.factorize(S);
if (SolverN.info() != Eigen::Success)
std::cout << "error here: factorize fail!" << std::endl;
SolverN.compute(S);
std::cout << "Smoothing 1\n";
v0 = TetLaplacianMatrix.transpose() * v0;
v0_sol = SolverN.solve(v0);
std::cout << "Smoothing 2\n";
v1 = TetLaplacianMatrix.transpose() * v1;
v1_sol = SolverN.solve(v1);
std::cout << "Smoothing 3\n";
v2 = TetLaplacianMatrix.transpose() * v2;
v2_sol = SolverN.solve(v2);
//std::cout << "Smoothing 4\n";
//v3 = TetLaplacianMatrix.transpose() * v3;
//v3_sol = SolverN.solve(v3);
for (GLKPOSITION tetPos = materialSpace->GetTetraList().GetHeadPosition(); tetPos;) {
QMeshTetra* tetra = (QMeshTetra*)materialSpace->GetTetraList().GetNext(tetPos);
int index = tetra->FieldIndexNumber;
Eigen::Vector3d newNormal(v0_sol(index), v1_sol(index), v2_sol(index));
newNormal.stableNormalize();
//newNormal = newNormal * v3_sol(index);
VectorFieldMatrix(index, 0) = newNormal.x();
VectorFieldMatrix(index, 1) = newNormal.y();
VectorFieldMatrix(index, 2) = newNormal.z();
}
}
void heatMethod::_inverseVolumeMatrix() {
int num = materialSpace->GetNodeNumber() - Num_nodesInConvexHull;
for (int i = 0; i < num; i++) {
if (VolumeMatrix.coeff(i, i) > 0.0001) {
VolumeMatrix.coeffRef(i, i) = 1.0 / VolumeMatrix.coeff(i, i);
}
else {
std::cout << "\nVol: " << VolumeMatrix.coeff(i, i) << std::endl;
}
}
}
void heatMethod::_generateVectorField() {
int num = materialSpace->GetTetraNumber();
int num_tets = num - Num_tetInConvexHull;
VectorFieldMatrix = Eigen::MatrixXd(num_tets, 3);
Eigen::MatrixXd T = Eigen::MatrixXd::Zero(3, 4);
Eigen::MatrixXd VertCoord = Eigen::MatrixXd::Zero(3, 3);
Eigen::Vector4d VertField = Eigen::Vector4d::Zero(4);
T(0, 0) = 1;
T(1, 1) = 1;
T(2, 2) = 1;
T(0, 3) = T(1, 3) = T(2, 3) = -1;
std::cout << "T: " << T << std::endl;
for (GLKPOSITION tetPos = materialSpace->GetTetraList().GetHeadPosition(); tetPos;) {
QMeshTetra* tet = (QMeshTetra*)materialSpace->GetTetraList().GetNext(tetPos);
for (int i = 0; i < 4; i++) {
QMeshNode* node = tet->GetNodeRecordPtr(i + 1);
double x, y, z;
node->GetCoord3D(x, y, z);
if (i != 3) {
VertCoord(i, 0) = x;
VertCoord(i, 1) = y;
VertCoord(i, 2) = z;
}
else {
for (int j = 0; j < 3; j++) {
VertCoord(j, 0) -= x;
VertCoord(j, 1) -= y;
VertCoord(j, 2) -= z;
}
}
VertField(i) = node->HeatFieldValue;
}
Eigen::Vector3d temp = VertCoord.inverse() * T * VertField;
temp.stableNormalize();
VectorFieldMatrix(tet->FieldIndexNumber, 0) = temp[0];
VectorFieldMatrix(tet->FieldIndexNumber, 1) = temp[1];
VectorFieldMatrix(tet->FieldIndexNumber, 2) = temp[2];
}
}
void heatMethod::_generateScalarField() {
int num = materialSpace->GetNodeNumber();
int num_nodes = num - Num_nodesInConvexHull;
Eigen::VectorXd divVector = Eigen::VectorXd::Zero(num_nodes);
_generateDivergence(divVector);
Eigen::SparseMatrix<double> invVol = VolumeMatrix;
Eigen::SparseMatrix<double> boundaryCompensator(num_nodes, num_nodes);
boundaryCompensator.setIdentity();
for (GLKPOSITION nodePos = materialSpace->GetNodeList().GetHeadPosition(); nodePos;) {
QMeshNode* node = (QMeshNode*)materialSpace->GetNodeList().GetNext(nodePos);
int ii = node->FieldIndexNumber;
if (node->isBoundary && node->isSource) {
invVol.coeffRef(ii, ii) = 0.0;
divVector(ii) = 0.0;
}
else {
invVol.coeffRef(ii, ii) = 1.0;
boundaryCompensator.coeffRef(ii, ii) = 0;
}
}
/*Eigen::ColPivHouseholderQR<Eigen::MatrixXd> dec(WeightMatrix);
Eigen::VectorXd u = dec.solve(divVector);*/
Eigen::PardisoLU <Eigen::SparseMatrix<double>> Solver;// (PardisoLU/SparseLU)
Eigen::SparseMatrix<double> S = invVol * WeightMatrix + boundaryCompensator;
S = 100 * S;
Solver.analyzePattern(S);
Solver.factorize(S);
if (Solver.info() != Eigen::Success)
std::cout << "error here: factorize fail!" << std::endl;
Solver.compute(S);
divVector = 100 * divVector;
Eigen::VectorXd u = Solver.solve(divVector);
std::cout << "System Solved for Scalar Field...\n";
double max = -999999, min = 99999;
for (GLKPOSITION pos = materialSpace->GetNodeList().GetHeadPosition(); pos;) {
QMeshNode* node = (QMeshNode*)materialSpace->GetNodeList().GetNext(pos);
int i = node->FieldIndexNumber;
node->HeatFieldValue = u[i];
if (u[i] > max) max = u[i];
if (u[i] < min) min = u[i];
}
double max2 = -999999, min2 = 99999;
for (GLKPOSITION pos = materialSpace->GetNodeList().GetHeadPosition(); pos;) {
QMeshNode* node = (QMeshNode*)materialSpace->GetNodeList().GetNext(pos);
int i = node->FieldIndexNumber;
node->HeatFieldValue = (u[i] - min) / (max - min);
if (node->HeatFieldValue > max2) max2 = node->HeatFieldValue;
if (node->HeatFieldValue < min2) min2 = node->HeatFieldValue;
node->scalarField = node->HeatFieldValue;
}
std::cout << "Final MAX: " << max2 << "Final MIN: " << min2 << std::endl;
}
void heatMethod::_generateDivergence(Eigen::VectorXd& divVector) {
std::cout << "Generating Divergence Field\n";
for (GLKPOSITION pos = materialSpace->GetTetraList().GetHeadPosition(); pos;) {
QMeshTetra* tet = (QMeshTetra*)materialSpace->GetTetraList().GetNext(pos);
for (int i = 1; i <= 4; i++) {
QMeshNode* node = (QMeshNode*)tet->GetNodeRecordPtr(i);
int node_index = node->FieldIndexNumber;
int tet_index = tet->FieldIndexNumber;
//int _facenumber = 999;
double Sk;
Eigen::Vector3d nk;
nk = _getOppositeNormalWithMag(node, tet);
Sk = 0.5 * abs(nk.stableNorm());
nk.stableNormalize();
/*switch(i) {
case(1): _facenumber = 2;
case(2): _facenumber = 3;
case(3): _facenumber = 4;
case(4): _facenumber = 1;
}*/
Eigen::Vector3d grad_vec(VectorFieldMatrix(tet_index, 0), VectorFieldMatrix(tet_index, 1), VectorFieldMatrix(tet_index, 2));
grad_vec.stableNormalize();
//QMeshFace* face = tet->GetFaceRecordPtr(_facenumber);
/*face->CalPlaneEquation();
face->CalArea();*/
// std::cout << "area: " << face->GetArea() << std::endl;
divVector[node_index] -= Sk * nk.dot(grad_vec) / 3;
}
}
}
Eigen::Vector3d heatMethod::_getOppositeNormalWithMag(QMeshNode* node, QMeshTetra* tet) {
QMeshNode* otNode1 = NULL, * otNode2 = NULL, * otNode3 = NULL;
int node_index_in_Tet = tet->GetNodeIndex(node);
for (int i = 1; i <= 4; i++) {
if (i != node_index_in_Tet) {
if (otNode1 == NULL) {
otNode1 = tet->GetNodeRecordPtr(i);
}
else if (otNode2 == NULL) {
otNode2 = tet->GetNodeRecordPtr(i);
}
else if (otNode3 == NULL) {
otNode3 = tet->GetNodeRecordPtr(i);
}
}
}
Eigen::Vector3d v1, v2, v3;
double x1, x2, x3, y1, y2, y3, z1, z2, z3;
otNode1->GetCoord3D(x1, y1, z1);
otNode2->GetCoord3D(x2, y2, z2);
otNode3->GetCoord3D(x3, y3, z3);
v1 = Eigen::Vector3d(x2 - x1, y2 - y1, z2 - z1);
v2 = Eigen::Vector3d(x3 - x1, y3 - y1, z3 - z1);
node->GetCoord3D(x2, y2, z2);
v3 = Eigen::Vector3d(x2 - x1, y2 - y1, z2 - z1);
Eigen::Vector3d nx = v1.cross(v2);
if (nx.dot(v3) < -0.0000001) {
nx = -1 * nx;
}
return nx;
}ac2468ac8This file is pinned to the selected release. Download the original to open it in your design tool.