|
|
@ -4,7 +4,7 @@ |
|
|
|
|
|
|
|
#ifndef TOP3D_TOP3D_H |
|
|
|
#define TOP3D_TOP3D_H |
|
|
|
|
|
|
|
#include <filesystem> |
|
|
|
#include "Util.h" |
|
|
|
#include "Material.hpp" |
|
|
|
#include "Mesh.h" |
|
|
@ -39,7 +39,7 @@ namespace top { |
|
|
|
), sp_material_(sp_material), sp_mesh_(sp_mesh) { |
|
|
|
F_ = SpMat(sp_mesh_->GetNumDofs(), 1); |
|
|
|
K_ = SpMat(sp_mesh_->GetNumDofs(), sp_mesh_->GetNumDofs()); |
|
|
|
spdlog::info("sizeof K: {}",K_.rows()); |
|
|
|
spdlog::info("DOF: {}", K_.rows()); |
|
|
|
spdlog::info("start to precompute..."); |
|
|
|
Precompute(); |
|
|
|
} |
|
|
@ -51,7 +51,7 @@ namespace top { |
|
|
|
if (directions[dir]) |
|
|
|
dofs_to_fixed_.insert(node_id_to_fix[i] * 3 + dir); |
|
|
|
} |
|
|
|
auto ttt=dofs_to_fixed_; |
|
|
|
auto ttt = dofs_to_fixed_; |
|
|
|
} |
|
|
|
|
|
|
|
void AddNBC(const Eigen::MatrixXi &NBC_coords, const Eigen::Vector3d &forces) { |
|
|
@ -59,95 +59,11 @@ namespace top { |
|
|
|
for (int i = 0; i < node_id_to_load.size(); ++i) { |
|
|
|
for (int dir = 0; dir < 3; ++dir) |
|
|
|
if (forces[dir]) |
|
|
|
F_.coeffRef(GetDof(node_id_to_load[i], dir),0) += forces(dir); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void TopOptMainLoop() { |
|
|
|
Tensor3d x = Tensor3d(sp_mesh_->GetLx(), sp_mesh_->GetLy(), sp_mesh_->GetLz()); |
|
|
|
x.setConstant(sp_para_->volfrac); |
|
|
|
Tensor3d xPhys = x; |
|
|
|
Eigen::VectorXd xPhys_col = Eigen::Map<Eigen::VectorXd>(xPhys.data(), xPhys.size()); |
|
|
|
int loop = 0; |
|
|
|
double change = 1.0; |
|
|
|
double E0 = sp_material_->YM; |
|
|
|
double Emin = sp_material_->YM * sp_para_->E_factor; |
|
|
|
|
|
|
|
// precompute
|
|
|
|
Eigen::VectorXd dv(sp_mesh_->GetNumEles()); |
|
|
|
dv.setOnes(); |
|
|
|
dv = H_ * (dv.array() / Hs_.array()).matrix().eval(); |
|
|
|
// start iteration
|
|
|
|
while (change > sp_para_->tol_x && loop < sp_para_->max_loop) { |
|
|
|
++loop; |
|
|
|
Eigen::VectorXd sK = (sKe_ * (Emin + xPhys_col.array().pow(sp_para_->penal) * |
|
|
|
(E0 - Emin)).matrix().transpose()).reshaped(); |
|
|
|
auto v_tri = Vec2Triplet(iK_, jK_, sK); |
|
|
|
K_.setFromTriplets(v_tri.begin(), v_tri.end()); |
|
|
|
IntroduceFixedDofs(K_, F_); |
|
|
|
#ifdef USE_SUITESPARSE |
|
|
|
|
|
|
|
Eigen::CholmodSupernodalLLT<Eigen::SparseMatrix<double>> solver; |
|
|
|
solver.compute(K_); |
|
|
|
Eigen::VectorXd U = solver.solve(F_); |
|
|
|
|
|
|
|
#else |
|
|
|
// dense direct method
|
|
|
|
Eigen::MatrixXd denseK = Eigen::MatrixXd(K_); |
|
|
|
Eigen::VectorXd U = denseK.fullPivLu().solve(Eigen::VectorXd(F_)); |
|
|
|
#endif |
|
|
|
// compliance
|
|
|
|
Eigen::VectorXd ce(sp_mesh_->GetNumEles()); |
|
|
|
for (int i = 0; i < sp_mesh_->GetNumEles(); ++i) { |
|
|
|
Eigen::VectorXi dofs_in_ele_i = sp_mesh_->MapEleId2Dofs(i); |
|
|
|
Eigen::VectorXd Ue = U(dofs_in_ele_i); |
|
|
|
ce(i) = Ue.transpose() * Ke_ * Ue; |
|
|
|
} |
|
|
|
double c = ce.transpose() * (Emin + xPhys_col.array().pow(sp_para_->penal) * (E0 - Emin)).matrix(); |
|
|
|
double v = xPhys_col.sum(); |
|
|
|
|
|
|
|
Eigen::VectorXd dc = |
|
|
|
-sp_para_->penal * (E0 - Emin) * xPhys_col.array().pow(sp_para_->penal - 1.0) * ce.array(); |
|
|
|
|
|
|
|
// mma solver
|
|
|
|
size_t num_constrants = 1; |
|
|
|
size_t num_variables = sp_mesh_->GetNumEles(); |
|
|
|
auto mma = std::make_shared<MMASolver>(num_variables, num_constrants); |
|
|
|
Eigen::VectorXd variables_tmp = xPhys_col; |
|
|
|
double f0val = c; |
|
|
|
Eigen::VectorXd df0dx = dc; |
|
|
|
double fval = v-sp_mesh_->GetNumEles()*sp_para_->volfrac; |
|
|
|
Eigen::VectorXd dfdx = dv; |
|
|
|
static Eigen::VectorXd low_bounds = Eigen::VectorXd::Zero(sp_mesh_->GetNumEles()); |
|
|
|
static Eigen::VectorXd up_bounds = Eigen::VectorXd::Ones(sp_mesh_->GetNumEles()); |
|
|
|
|
|
|
|
// spdlog::info("mma update");
|
|
|
|
mma->Update(variables_tmp.data(), df0dx.data(), &fval, dfdx.data(), |
|
|
|
low_bounds.data(), up_bounds.data()); |
|
|
|
|
|
|
|
change = (variables_tmp - xPhys_col).cwiseAbs().maxCoeff(); |
|
|
|
xPhys_col = variables_tmp; |
|
|
|
spdlog::critical("Iter: {:3d}, Comp: {:.3f}, Vol: {:.2f}, Change: {:.3f}", loop, c, v, change); |
|
|
|
#ifdef WRITE_TENSOR |
|
|
|
Tensor3d ten_xPhys_to_write(sp_mesh_->GetNumEles(), 1, 1); |
|
|
|
for (int i = 0; i < xPhys_col.size(); ++i) { |
|
|
|
ten_xPhys_to_write(i, 0, 0) = xPhys_col(i); |
|
|
|
F_.coeffRef(GetDof(node_id_to_load[i], dir), 0) += forces(dir); |
|
|
|
} |
|
|
|
ten_xPhys_to_write=ten_xPhys_to_write.reshape(Eigen::array<int,3>{sp_mesh_->GetLx(),sp_mesh_->GetLy(),sp_mesh_->GetLz()}); |
|
|
|
write_tensor3d(CMAKE_SOURCE_DIR "/output/txt/iter_" + std::to_string(loop)+".txt", ten_xPhys_to_write); |
|
|
|
write_tensor3d_to_vtk(CMAKE_SOURCE_DIR "/output/vtk/iter_" + std::to_string(loop)+".vtk", ten_xPhys_to_write); |
|
|
|
#endif |
|
|
|
} |
|
|
|
// result
|
|
|
|
Tensor3d ten_xPhys_to_write(sp_mesh_->GetNumEles(), 1, 1); |
|
|
|
for (int i = 0; i < xPhys_col.size(); ++i) { |
|
|
|
ten_xPhys_to_write(i, 0, 0) = xPhys_col(i); |
|
|
|
} |
|
|
|
ten_xPhys_to_write=ten_xPhys_to_write.reshape(Eigen::array<int,3>{sp_mesh_->GetLx(),sp_mesh_->GetLy(),sp_mesh_->GetLz()}); |
|
|
|
write_tensor3d(CMAKE_SOURCE_DIR "/output/txt/iter_" + std::to_string(loop)+".txt", ten_xPhys_to_write); |
|
|
|
write_tensor3d_to_vtk(CMAKE_SOURCE_DIR "/output/vtk/iter_" + std::to_string(loop)+".vtk", ten_xPhys_to_write); |
|
|
|
|
|
|
|
} |
|
|
|
void TopOptMainLoop(); |
|
|
|
|
|
|
|
private: |
|
|
|
|
|
|
@ -158,59 +74,7 @@ namespace top { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void Precompute() { |
|
|
|
Eigen::MatrixXi mat_ele2dofs = sp_mesh_->GetEleId2DofsMap(); |
|
|
|
iK_ = Eigen::KroneckerProduct(mat_ele2dofs, Eigen::VectorXi::Ones(24)).transpose().reshaped(); |
|
|
|
jK_ = Eigen::KroneckerProduct(mat_ele2dofs, Eigen::RowVectorXi::Ones(24)).transpose().reshaped(); |
|
|
|
sp_material_->computeKe(0.5, 0.5, 0.5, sp_material_->D, Ke_); |
|
|
|
sKe_ = Ke_.reshaped(); |
|
|
|
|
|
|
|
// precompute filter
|
|
|
|
Eigen::VectorXi iH = Eigen::VectorXi::Ones( |
|
|
|
sp_mesh_->GetNumEles() * std::pow(2.0 * (std::ceil(sp_para_->r_min) - 1.0) + 1, 3)); |
|
|
|
Eigen::VectorXi jH = iH; |
|
|
|
Eigen::VectorXd sH(iH.size()); |
|
|
|
sH.setZero(); |
|
|
|
int cnt = 0; |
|
|
|
int delta = std::ceil(sp_para_->r_min) - 1; |
|
|
|
for (int k = 0; k < sp_mesh_->GetLz(); ++k) { |
|
|
|
for (int j = 0; j < sp_mesh_->GetLy(); ++j) { |
|
|
|
for (int i = 0; i < sp_mesh_->GetLx(); ++i) { |
|
|
|
int ele_id0 = sp_mesh_->MapEleCoord2Id((Eigen::MatrixXi(1, 3) << i, j, k).finished())(0); |
|
|
|
for (int k2 = std::max(k - delta, 0); k2 <= std::min(k + delta, sp_mesh_->GetLz() - 1); ++k2) { |
|
|
|
for (int j2 = std::max(j - delta, 0); |
|
|
|
j2 <= std::min(j + delta, sp_mesh_->GetLy() - 1); ++j2) { |
|
|
|
for (int i2 = std::max(i - delta, 0); |
|
|
|
i2 <= std::min(i + delta, sp_mesh_->GetLx() - 1); ++i2) { |
|
|
|
int ele_id1 = sp_mesh_->MapEleCoord2Id( |
|
|
|
(Eigen::MatrixXi(1, 3) << i2, j2, k2).finished())(0); |
|
|
|
iH(cnt) = ele_id0; |
|
|
|
jH(cnt) = ele_id1; |
|
|
|
sH(cnt) = std::max(0.0, |
|
|
|
sp_para_->r_min - |
|
|
|
Eigen::Vector3d(i - i2, j - j2, k - k2).norm()); |
|
|
|
++cnt; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
std::vector<Eigen::Triplet<double>> v_tri; |
|
|
|
for (int i = 0; i < cnt; ++i) { |
|
|
|
v_tri.push_back({iH(i), jH(i), sH(i)}); |
|
|
|
} |
|
|
|
|
|
|
|
H_ = SpMat(sp_mesh_->GetNumEles(), sp_mesh_->GetNumEles()); |
|
|
|
H_.setFromTriplets(v_tri.begin(), v_tri.end()); |
|
|
|
|
|
|
|
Hs_ = Eigen::VectorXd(sp_mesh_->GetNumEles()); |
|
|
|
for (int i = 0; i < Hs_.size(); ++i) { |
|
|
|
Hs_(i) = H_.row(i).sum(); |
|
|
|
} |
|
|
|
} |
|
|
|
void Precompute(); |
|
|
|
|
|
|
|
int GetDof(int node_id, int dir) { |
|
|
|
return node_id * 3 + dir; |
|
|
|