// // Created by cflin on 4/20/23. // #ifndef TOP3D_TOP3D_H #define TOP3D_TOP3D_H #include #include #include #include #include #include #include #include #include #include "Util.h" #include "Material.hpp" #include "Mesh.h" #include "Boundary.h" #include "IrregularMesh.h" namespace da::sha { namespace top { struct CtrlPara { double volfrac = 0.5; double penal = 1.0; int max_loop = 100; double r_min = 2.0; double tol_x = 0.01; double E_factor = 1e-9; }; class Top3d { public: Top3d(std::shared_ptr sp_para, std::shared_ptr sp_material, std::shared_ptr sp_mesh) : sp_para_(sp_para ), sp_material_(sp_material), sp_mesh_(sp_mesh) { F_ = SpMat(sp_mesh_->GetNumDofs(), 1); K_ = SpMat(sp_mesh_->GetNumDofs(), sp_mesh_->GetNumDofs()); spdlog::info("DOF: {}", K_.rows()); spdlog::info("start to precompute..."); Precompute(); } /// add Dirichlet boundary condition /// \param DBC_coords nx3, mesh coordinates to fixed /// \param directions 1x[3|1], directions([0|1|2])!=0 means that fixing [x|y|z] direction; Only directions(0) will be use for head_condition void AddDBC(const Eigen::MatrixXi &DBC_coords, const Eigen::Vector3i &directions) { Eigen::VectorXi node_id_to_fix = sp_mesh_->MapNodeCoord2Id(DBC_coords); for (int i = 0; i < node_id_to_fix.size(); ++i) { for (int dir = 0; dir < sp_mesh_->Get_DOFS_EACH_NODE(); ++dir) if (directions[dir]) dofs_to_fixed_.insert(GetDof(node_id_to_fix[i],dir)); } } void AddDBC(const Eigen::MatrixXd & DBC_coords,const Eigen::Vector3i &directions){ Eigen::MatrixXi low_DBC_coords=DBC_coords.cast(); Eigen::MatrixXi around_low=Eigen::MatrixXi(low_DBC_coords.rows()*8,3); static const Eigen::MatrixXi delta_coord = (Eigen::MatrixXi(8, 3) << 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1 ).finished(); for(int i=0;i(); Eigen::MatrixXd local_coords=(NBC_coords-low_DBC_coords.cast()).array()*2.0-1.0;// map coords to [-1,1] Eigen::VectorXi ele_ids=sp_mesh_->MapEleCoord2Id(low_DBC_coords); for(int i=0;iMapEleId2Dofs(ele_ids(i)); Eigen::Matrix N; // sp_material_->computeN(Eigen::RowVector3d(local_coords(i,0),local_coords(i,1),local_coords(i,2)), N);//TODO: fixme Eigen::VectorXd node_forces=N.transpose()*forces; for(int dofi=0;dofiMapNodeCoord2Id(NBC_coords); for (int i = 0; i < node_id_to_load.size(); ++i) { for (int dir = 0; dir Get_DOFS_EACH_NODE(); ++dir) if (forces[dir]) F_.coeffRef(GetDof(node_id_to_load[i], dir), 0) += forces(dir); } } Tensor3d TopOptMainLoop(); std::vector GetTensorOfStress(const Eigen::VectorXd &which_col_of_stress); Tensor3d GetRhoFieldOneFilled()const{ return rho_field_one_filled_; } Tensor3d GetRhoFieldZeroFilled()const{ return rho_field_zero_filled_; } private: Tensor3d GetTensorFromCol(const Eigen::VectorXd & proprty_col); void IntroduceFixedDofs(Eigen::SparseMatrix &K, Eigen::SparseMatrix &F) { for (auto dof: dofs_to_fixed_) { K.coeffRef(dof, dof) *= 1e10; F.coeffRef(dof, 0) = 0; } } void Precompute(); int GetDof(int node_id, int dir) { return node_id * sp_mesh_->Get_DOFS_EACH_NODE() + dir; } private: std::shared_ptr sp_para_; std::shared_ptr sp_material_; std::shared_ptr sp_mesh_; private: SpMat F_; Eigen::VectorXi iK_, jK_; Eigen::VectorXd sKe_; Eigen::MatrixXd Ke_; SpMat K_; std::set dofs_to_fixed_; SpMat H_; Eigen::VectorXd Hs_; // result Eigen::VectorXd U_; Eigen::VectorXd rho_; Tensor3d rho_field_one_filled_; Tensor3d rho_field_zero_filled_; }; } // top } // da::sha #endif //TOP3D_TOP3D_H