Browse Source

fix shape functions && add example 'box'

multiple_top
Hilda-oo 1 year ago
parent
commit
dedaab4fa2
  1. 1
      .gitignore
  2. 9
      examples/top-thermoelastic-BiclampedStructure/main.cpp
  3. 6
      examples/top-thermoelastic-box/CMakeLists.txt
  4. 80
      examples/top-thermoelastic-box/config.json
  5. 195
      examples/top-thermoelastic-box/main.cpp
  6. 12
      src/FEA/ThermalLinearFEA.cpp
  7. 4
      src/ThermoelasticTop3d.h
  8. 33
      src/Top3d.cpp
  9. 1
      src/Top3d.h

1
.gitignore

@ -1,3 +1,4 @@
.cache/
cmake-*/ cmake-*/
build/ build/
.idea/ .idea/

9
examples/top-thermoelastic-BiclampedStructure/main.cpp

@ -159,6 +159,15 @@ int main() {
spdlog::info("write displacement norm vtk to: {}", U_vtk_path.c_str()); spdlog::info("write displacement norm vtk to: {}", U_vtk_path.c_str());
// extract stress field(txt or vtk) // extract stress field(txt or vtk)
auto vonStress = ther_top3d.GetVonStress();
fs_path stressVon_txt_pah = output_dir / "txt" / (condition + "_stressVon.txt");
write_tensor3d(stressVon_txt_pah, vonStress, sp_mech_mesh->GetOrigin(),
sp_mech_mesh->GetOrigin() + sp_mech_mesh->GetLenBox());
spdlog::info("write stressVon txt to: {}", stressVon_txt_pah.c_str());
fs_path stressVon_vtk_pah = output_dir / "vtk" / (condition + "_stressVon.vtk");
WriteTensorToVtk(stressVon_vtk_pah, vonStress, sp_mech_mesh);
spdlog::info("write stressVon vtk to: {}", stressVon_vtk_pah.c_str());
auto v_tenosr = ther_top3d.GetTensorOfStress(Eigen::Vector3d{0, 1, 2}); auto v_tenosr = ther_top3d.GetTensorOfStress(Eigen::Vector3d{0, 1, 2});
fs_path stressX_txt_pah = output_dir / "txt" / (condition + "_stressX.txt"); fs_path stressX_txt_pah = output_dir / "txt" / (condition + "_stressX.txt");
write_tensor3d(stressX_txt_pah, v_tenosr[0], sp_mech_mesh->GetOrigin(), write_tensor3d(stressX_txt_pah, v_tenosr[0], sp_mech_mesh->GetOrigin(),

6
examples/top-thermoelastic-box/CMakeLists.txt

@ -0,0 +1,6 @@
set(SUB_PROJECT_NAME top-thermoelastic-box)
add_executable(${SUB_PROJECT_NAME} main.cpp)
target_link_libraries(${SUB_PROJECT_NAME} ${PROJECT_NAME}_lib)
target_compile_definitions(${SUB_PROJECT_NAME} PUBLIC CONFIG_FILE="${CMAKE_CURRENT_SOURCE_DIR}/config.json")
target_compile_definitions(${SUB_PROJECT_NAME} PUBLIC OUTPUT_DIR="${CMAKE_SOURCE_DIR}/output")
target_compile_definitions(${SUB_PROJECT_NAME} PUBLIC ASSETS_DIR="${CMAKE_SOURCE_DIR}/assets")

80
examples/top-thermoelastic-box/config.json

@ -0,0 +1,80 @@
{
"TopologyOptimizationExample": "box","//": "USER DEFINED project name",
"material": {
"E": 7.2e10, "//": "Young's modulus",
"poisson_ratio": 0.3, "//": "Poisson's ratio",
"thermal_conductivity":237, "//unit": "W/(m*K)",
"thermal_expansion_coefficient": 2.321e-5, "//unit": "1/K"
},
"topology": {
"max_loop": 150,"//": "Maximum number of iterations for topology optimization",
"volfrac": 0.3,"//": "0~1, Volume ratio restriction",
"penal": 3.0,"//": "Useless",
"r_min": 1.05,"//": "Convolution kernel size, less than 1 will result in checkerboard phenomenon",
"T_ref": 293.15,"//": "K, Reference/Environment temperature",
"T_limit": 294,"//": "K, Maximum temperature limit in optimization",
"R_E": 28,"//": "1~28, The higher the value, the closer the density is to 0 or 1",
"R_lambda": 28,"//": "1~28, The higher the value, the closer the density is to 0 or 1",
"R_beta":0,"//": "Useless"
},
"model": {
"regular_model": {
"lx": 100,"//": "A lx * ly * lz rectangle",
"ly": 30,
"lz": 30
}
},
"mechanical_boundary_condition":{ "//": "A [min[0],max[0]] * [min[1],max[1]] * [min[2],max[2]] rectangle boundary",
"//": "NBC: Neumann boundary condition; DBC: Dirichlet boundary condition",
"NBC": [
{
"min": [-0.01, 0.97, -0.01],"//": "0~1, A [min[0],max[0]] line, because y and z are the same",
"max": [1.01, 1.01, 1.01],"//": "0~1",
"val": [0, -1e9, 0],"//": "Pa, The z direction is subject to a -1e8 load"
}
],
"DBC": [
{
"min": [-0.01, -0.01, -0.01],
"max": [1.01, 0.05, 1.01],
"dir": [1, 1, 1],"//": "0 or 1, indicates whether xyz directions are fixed"
}
]
},
"thermal_boundary_condition": {
"NBC": [
{
"min": [-0.01, 0.97, -0.01],
"max": [1.01, 1.01, 1.01],
"heat_flux": 0.18, "//": "W, >=0,18.355 for 324"
}
],
"DBC": [
{
"min": [0.07, 0.45, -0.01],
"max": [0.12, 0.58, 1.01],
"temperature": 293.15, "//": "K, fixed temperature in DBC"
},
{
"min": [0.27, 0.40, -0.01],
"max": [0.32, 0.55, 1.01],
"temperature": 293.15, "//": "K, fixed temperature in DBC"
},
{
"min": [0.46, 0.40, -0.01],
"max": [0.53, 0.55, 1.01],
"temperature": 293.15, "//": "K, fixed temperature in DBC"
},
{
"min": [0.67, 0.40, -0.01],
"max": [0.72, 0.55, 1.01],
"temperature": 293.15, "//": "K, fixed temperature in DBC"
},
{
"min": [0.87, 0.40, -0.01],
"max": [0.92, 0.57, 1.01],
"temperature": 293.15, "//": "K, fixed temperature in DBC"
}
]
}
}

195
examples/top-thermoelastic-box/main.cpp

@ -0,0 +1,195 @@
//
// Created by cflin on 6/9/23.
//
#include <memory>
#include <nlohmann/json.hpp>
#include "Boundary.h"
#include "Mesh/HeatMesh.h"
#include "Util.h"
#include "ThermoelasticTop3d.h"
#include "FEA/MechanicalLinearFEA.h"
#include "FEA/ThermalLinearFEA.h"
#include "TensorWrapper.h"
int main() {
using namespace da::sha;
using top::fs_path;
using std::string;
top::fs_path output_dir(OUTPUT_DIR);
top::fs_path config_file(CONFIG_FILE);
top::fs_path assets_dir(ASSETS_DIR);
spdlog::info("Algo read from '{}'", config_file.string());
spdlog::info("Algo output to '{}'", output_dir.string());
spdlog::info("assets dir: '{}'", assets_dir.string());
// read json
std::ifstream f(config_file.c_str());
if (!f) {
spdlog::critical("f open fail!");
exit(-7);
}
nlohmann::json j_config = nlohmann::json::parse(f);
// read title
std::string condition = j_config["TopologyOptimizationExample"];
spdlog::critical("TopologyOptimizationExample: {}", condition);
// set topology parameters
auto para = std::make_shared<top::CtrlPara>();
para->max_loop = j_config["topology"]["max_loop"];
para->volfrac = j_config["topology"]["volfrac"];
para->r_min = j_config["topology"]["r_min"];
para->penal = j_config["topology"]["penal"];
para->T_ref = j_config["topology"]["T_ref"];
para->T_limit = j_config["topology"]["T_limit"];
para->R_E = j_config["topology"]["R_E"];
para->R_lambda = j_config["topology"]["R_lambda"];
para->R_beta = j_config["topology"]["R_beta"];
// set material parameters
double E = j_config["material"]["E"];
double Poisson_ratio = j_config["material"]["poisson_ratio"];
double thermal_conductivity = j_config["material"]["thermal_conductivity"];
double thermal_expansion_coefficient = j_config["material"]["thermal_expansion_coefficient"];
auto material = std::make_shared<top::Material>(E, Poisson_ratio, thermal_conductivity,
thermal_expansion_coefficient);
// set fea
auto sp_mech_fea = std::make_shared<top::MechanicalLinearFEA>(material);// for mechanical
auto sp_thermal_fea = std::make_shared<top::ThermalLinearFEA>(material);// for thermal
// set mesh(regular)
int len_x = j_config["model"]["regular_model"]["lx"];
int len_y = j_config["model"]["regular_model"]["ly"];
int len_z = j_config["model"]["regular_model"]["lz"];
std::shared_ptr<top::Mesh> sp_mech_mesh;
std::shared_ptr<top::HeatMesh> sp_thermal_mesh;
sp_mech_mesh = std::make_shared<top::Mesh>(len_x, len_y, len_z);
sp_thermal_mesh = std::make_shared<top::HeatMesh>(len_x, len_y, len_z);
// initialize Top3d
auto sp_mech_top3d = std::make_shared<top::Top3d>(para, sp_mech_fea, sp_mech_mesh);
auto sp_thermal_top3d = std::make_shared<top::Top3d>(para, sp_thermal_fea, sp_thermal_mesh);
// auxiliary class(Boundary) help to get boundary coordinates
// see the comments in Boundary.h for more information
top::Boundary mech_bdr(sp_mech_mesh);
top::Boundary thermal_bdr(sp_thermal_mesh);
{
// add Dirichlet boundary, see the comments in Top3d::AddDBC for more information
assert(j_config.count("mechanical_boundary_condition"));
assert(j_config["mechanical_boundary_condition"].count("DBC"));
assert(j_config["mechanical_boundary_condition"].count("NBC"));
int DBCNum = j_config["mechanical_boundary_condition"]["DBC"].size();
for (int _i = 0; _i < DBCNum; ++_i) {
const auto &DBCI = j_config["mechanical_boundary_condition"]["DBC"][_i];
Eigen::Vector3d minBBox(DBCI["min"][0], DBCI["min"][1], DBCI["min"][2]);
Eigen::Vector3d maxBBox(DBCI["max"][0], DBCI["max"][1], DBCI["max"][2]);
Eigen::Vector3i dir(DBCI["dir"][0], DBCI["dir"][1], DBCI["dir"][2]);
top::Dir t_dir(minBBox, maxBBox, dir);
sp_mech_top3d->AddDBC(mech_bdr.GetChosenCoordsByRelativeAlignedBox(t_dir.box),
t_dir.dir);
}
// add Neumann boundary, see the comments in Top3d::AddNBC for more information
int NBCNum = j_config["mechanical_boundary_condition"]["NBC"].size();
for (int _i = 0; _i < NBCNum; ++_i) {
const auto &NBCI = j_config["mechanical_boundary_condition"]["NBC"][_i];
Eigen::Vector3d minBBox(NBCI["min"][0], NBCI["min"][1], NBCI["min"][2]);
Eigen::Vector3d maxBBox(NBCI["max"][0], NBCI["max"][1], NBCI["max"][2]);
Eigen::Vector3d val(NBCI["val"][0], NBCI["val"][1], NBCI["val"][2]);
top::Neu t_neu(minBBox, maxBBox, val);
Eigen::MatrixXi coords = mech_bdr.GetChosenCoordsByRelativeAlignedBox(t_neu.box);
sp_mech_top3d->AddNBC(coords, t_neu.val / coords.rows());
}
}
{
// add Dirichlet boundary, see the comments in Top3d::AddDBC for more information
assert(j_config.count("thermal_boundary_condition"));
assert(j_config["thermal_boundary_condition"].count("DBC"));
assert(j_config["thermal_boundary_condition"].count("NBC"));
int DBCNum = j_config["thermal_boundary_condition"]["DBC"].size();
for (int _i = 0; _i < DBCNum; ++_i) {
const auto &DBCI = j_config["thermal_boundary_condition"]["DBC"][_i];
Eigen::Vector3d minBBox(DBCI["min"][0], DBCI["min"][1], DBCI["min"][2]);
Eigen::Vector3d maxBBox(DBCI["max"][0], DBCI["max"][1], DBCI["max"][2]);
top::Dir t_dir(minBBox, maxBBox, Eigen::Vector3i(1, 0, 0));
sp_thermal_top3d->AddDBC(mech_bdr.GetChosenCoordsByRelativeAlignedBox(t_dir.box),
t_dir.dir, DBCI["temperature"]);
}
// add Neumann boundary, see the comments in Top3d::AddNBC for more information
int NBCNum = j_config["thermal_boundary_condition"]["NBC"].size();
for (int _i = 0; _i < NBCNum; ++_i) {
const auto &NBCI = j_config["thermal_boundary_condition"]["NBC"][_i];
Eigen::Vector3d minBBox(NBCI["min"][0], NBCI["min"][1], NBCI["min"][2]);
Eigen::Vector3d maxBBox(NBCI["max"][0], NBCI["max"][1], NBCI["max"][2]);
Eigen::Vector3d val(NBCI["heat_flux"], 0, 0);
top::Neu t_neu(minBBox, maxBBox, val);
Eigen::MatrixXi coords = mech_bdr.GetChosenCoordsByRelativeAlignedBox(t_neu.box);
sp_thermal_top3d->AddNBC(coords, t_neu.val / coords.rows());
}
}
// init thermoelastic top3d
top::ThermoelasticTop3d ther_top3d(sp_mech_top3d, sp_thermal_top3d);
// process topology optimization
top::Tensor3d ten_rho = ther_top3d.TopOptMainLoop();
// extract rho (txt or vtk)
fs_path rho_txt_path = output_dir / "txt" / (condition + "_rho.txt");
write_tensor3d(rho_txt_path, ten_rho, sp_mech_mesh->GetOrigin(),
sp_mech_mesh->GetOrigin() + sp_mech_mesh->GetLenBox());
spdlog::info("write density txt to: {}", rho_txt_path.c_str());
fs_path rho_vtk_path = output_dir / "vtk" / (condition + "_rho.vtk");
WriteTensorToVtk(rho_vtk_path, ten_rho, sp_mech_mesh);
spdlog::info("write density vtk to: {}", rho_vtk_path.c_str());
// extract temperature(vtk)
fs_path U_vtk_path = output_dir / "vtk" / (condition + "_U.vtk");
WriteUToVtk(U_vtk_path, ther_top3d.GetTemperature(), sp_mech_mesh);
spdlog::info("write displacement norm vtk to: {}", U_vtk_path.c_str());
// extract stress field(txt or vtk)
auto vonStress = ther_top3d.GetVonStress();
fs_path stressVon_txt_pah = output_dir / "txt" / (condition + "_stressVon.txt");
write_tensor3d(stressVon_txt_pah, vonStress, sp_mech_mesh->GetOrigin(),
sp_mech_mesh->GetOrigin() + sp_mech_mesh->GetLenBox());
spdlog::info("write stressVon txt to: {}", stressVon_txt_pah.c_str());
fs_path stressVon_vtk_pah = output_dir / "vtk" / (condition + "_stressVon.vtk");
WriteTensorToVtk(stressVon_vtk_pah, vonStress, sp_mech_mesh);
spdlog::info("write stressVon vtk to: {}", stressVon_vtk_pah.c_str());
auto v_tenosr = ther_top3d.GetTensorOfStress(Eigen::Vector3d{0, 1, 2});
fs_path stressX_txt_pah = output_dir / "txt" / (condition + "_stressX.txt");
write_tensor3d(stressX_txt_pah, v_tenosr[0], sp_mech_mesh->GetOrigin(),
sp_mech_mesh->GetOrigin() + sp_mech_mesh->GetLenBox());
spdlog::info("write stressX txt to: {}", stressX_txt_pah.c_str());
fs_path stressX_vtk_path = output_dir / "vtk" / (condition + "_stressX.vtk");
WriteTensorToVtk(stressX_vtk_path, v_tenosr[0], sp_mech_mesh);
spdlog::info("write stressX vtk to: {}", stressX_vtk_path.c_str());
fs_path stressY_txt_pah = output_dir / "txt" / (condition + "_stressY.txt");
write_tensor3d(stressY_txt_pah, v_tenosr[1], sp_mech_mesh->GetOrigin(),
sp_mech_mesh->GetOrigin() + sp_mech_mesh->GetLenBox());
spdlog::info("write stressY txt to: {}", stressY_txt_pah.c_str());
fs_path stressY_vtk_path = output_dir / "vtk" / (condition + "_stressY.vtk");
WriteTensorToVtk(stressY_vtk_path, v_tenosr[1], sp_mech_mesh);
spdlog::info("write stressY vtk to: {}", stressY_vtk_path.c_str());
fs_path stressZ_txt_pah = output_dir / "txt" / (condition + "_stressZ.txt");
write_tensor3d(stressZ_txt_pah, v_tenosr[2], sp_mech_mesh->GetOrigin(),
sp_mech_mesh->GetOrigin() + sp_mech_mesh->GetLenBox());
spdlog::info("write stressZ txt to: {}", stressZ_txt_pah.c_str());
fs_path stressZ_vtk_path = output_dir / "vtk" / (condition + "_stressZ.vtk");
WriteTensorToVtk(stressZ_vtk_path, v_tenosr[2], sp_mech_mesh);
spdlog::info("write stressZ vtk to: {}", stressZ_vtk_path.c_str());
}

12
src/FEA/ThermalLinearFEA.cpp

@ -135,19 +135,19 @@ namespace da {
Eigen::Matrix<double, 3, 8> dNi; Eigen::Matrix<double, 3, 8> dNi;
dNi(0, 0) = 0.125 * -1 * (1.0 - y) * (1.0 - z); dNi(0, 0) = 0.125 * -1 * (1.0 - y) * (1.0 - z);
dNi(0, 1) = 0.125 * 1 * (1.0 - y) * (1.0 - z); dNi(0, 1) = 0.125 * 1 * (1.0 - y) * (1.0 - z);
dNi(0, 2) = 0.125 * 1 * (1.0 - y) * (1.0 - z); dNi(0, 2) = 0.125 * 1 * (1.0 + y) * (1.0 - z);
dNi(0, 3) = 0.125 * -1 * (1.0 + y) * (1.0 - z); dNi(0, 3) = 0.125 * -1 * (1.0 + y) * (1.0 - z);
dNi(0, 4) = 0.125 * -1 * (1.0 + y) * (1.0 - z); dNi(0, 4) = 0.125 * -1 * (1.0 - y) * (1.0 + z);
dNi(0, 5) = 0.125 * 1 * (1.0 - y) * (1.0 + z); dNi(0, 5) = 0.125 * 1 * (1.0 - y) * (1.0 + z);
dNi(0, 6) = 0.125 * 1 * (1.0 - y) * (1.0 + z); dNi(0, 6) = 0.125 * 1 * (1.0 + y) * (1.0 + z);
dNi(0, 7) = 0.125 * -1 * (1.0 + y) * (1.0 + z); dNi(0, 7) = 0.125 * -1 * (1.0 + y) * (1.0 + z);
dNi(1, 0) = 0.125 * (1.0 - x) * -1 * (1.0 - z); dNi(1, 0) = 0.125 * (1.0 - x) * -1 * (1.0 - z);
dNi(1, 1) = 0.125 * (1.0 + x) * -1 * (1.0 - z); dNi(1, 1) = 0.125 * (1.0 + x) * -1 * (1.0 - z);
dNi(1, 2) = 0.125 * (1.0 + x) * -1 * (1.0 - z); dNi(1, 2) = 0.125 * (1.0 + x) * +1 * (1.0 - z);
dNi(1, 3) = 0.125 * (1.0 - x) * +1 * (1.0 - z); dNi(1, 3) = 0.125 * (1.0 - x) * +1 * (1.0 - z);
dNi(1, 4) = 0.125 * (1.0 - x) * +1 * (1.0 - z); dNi(1, 4) = 0.125 * (1.0 - x) * -1 * (1.0 + z);
dNi(1, 5) = 0.125 * (1.0 + x) * -1 * (1.0 + z); dNi(1, 5) = 0.125 * (1.0 + x) * -1 * (1.0 + z);
dNi(1, 6) = 0.125 * (1.0 + x) * -1 * (1.0 + z); dNi(1, 6) = 0.125 * (1.0 + x) * +1 * (1.0 + z);
dNi(1, 7) = 0.125 * (1.0 - x) * +1 * (1.0 + z); dNi(1, 7) = 0.125 * (1.0 - x) * +1 * (1.0 + z);
dNi(2, 0) = 0.125 * (1.0 - x) * (1.0 - y) * -1; dNi(2, 0) = 0.125 * (1.0 - x) * (1.0 - y) * -1;
dNi(2, 1) = 0.125 * (1.0 + x) * (1.0 - y) * -1; dNi(2, 1) = 0.125 * (1.0 + x) * (1.0 - y) * -1;

4
src/ThermoelasticTop3d.h

@ -25,6 +25,10 @@ namespace da::sha::top {
return sp_mech_top3d_->GetTensorOfStress(which_col_of_stress); return sp_mech_top3d_->GetTensorOfStress(which_col_of_stress);
} }
Tensor3d GetVonStress(){
return sp_mech_top3d_->GetVonStress();
}
private: private:
void Precompute() { void Precompute() {
i_dFth_dT_ = Eigen::KroneckerProduct( i_dFth_dT_ = Eigen::KroneckerProduct(

33
src/Top3d.cpp

@ -178,6 +178,39 @@ namespace da::sha {
return vt; return vt;
} }
Tensor3d Top3d::GetVonStress() {
Eigen::VectorXd ele_to_write =
Eigen::VectorXd::Zero(
sp_mesh_->GetLx() * sp_mesh_->GetLy() * sp_mesh_->GetLz());
Eigen::VectorXi pixel_idx = sp_mesh_->GetGlobalIdxOfEleInUse();
// stress
Eigen::MatrixXd mat_stress(sp_mesh_->GetNumEles(), 6);
Eigen::MatrixXd B = sp_fea_->computeBe({0, 0, 0});
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);
mat_stress.row(i) = rho_(i) * sp_fea_->computeD() * B * Ue;
}
// fill
Tensor3d vt;
auto computeVonStress = [&](Eigen::VectorXd stress) -> double {
double x = stress(0);
double y = stress(1);
double z = stress(2);
double xy = stress(3);
double yz = stress(4);
double zx = stress(5);
return sqrt(0.5 * (x * x + y * y + z * z) + 3 * (xy * xy + yz * yz + zx * zx));
};
Eigen::VectorXd vonStress = Eigen::VectorXd::Zero(mat_stress.rows());
for (int i = 0; i < sp_mesh_->GetNumEles(); ++i) {
vonStress(i) = computeVonStress(mat_stress.row(i));
}
ele_to_write(pixel_idx) = vonStress;
vt = GetTensorFromCol(ele_to_write);
return vt;
}
Tensor3d Top3d::GetTensorFromCol(const Eigen::VectorXd &proprty_col) { Tensor3d Top3d::GetTensorFromCol(const Eigen::VectorXd &proprty_col) {
Tensor3d ten_prop_to_write(sp_mesh_->GetLx() * sp_mesh_->GetLy() * sp_mesh_->GetLz(), 1, Tensor3d ten_prop_to_write(sp_mesh_->GetLx() * sp_mesh_->GetLy() * sp_mesh_->GetLz(), 1,
1); 1);

1
src/Top3d.h

@ -133,6 +133,7 @@ namespace da::sha {
std::vector<Tensor3d> GetTensorOfStress(const Eigen::VectorXd &which_col_of_stress); std::vector<Tensor3d> GetTensorOfStress(const Eigen::VectorXd &which_col_of_stress);
Tensor3d GetVonStress();
Tensor3d GetRhoFieldOneFilled() const { Tensor3d GetRhoFieldOneFilled() const {
return rho_field_one_filled_; return rho_field_one_filled_;

Loading…
Cancel
Save