| 
						
						
							
								
							
						
						
					 | 
					@ -4,7 +4,7 @@ | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#ifndef TOP3D_TOP3D_H | 
					 | 
					 | 
					#ifndef TOP3D_TOP3D_H | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#define TOP3D_TOP3D_H | 
					 | 
					 | 
					#define TOP3D_TOP3D_H | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					
 | 
					 | 
					 | 
					#include <filesystem> | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					#include "Util.h" | 
					 | 
					 | 
					#include "Util.h" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#include "Material.hpp" | 
					 | 
					 | 
					#include "Material.hpp" | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					#include "Mesh.h" | 
					 | 
					 | 
					#include "Mesh.h" | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
					@ -39,7 +39,7 @@ namespace top { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        ), sp_material_(sp_material), sp_mesh_(sp_mesh) { | 
					 | 
					 | 
					        ), sp_material_(sp_material), sp_mesh_(sp_mesh) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            F_ = SpMat(sp_mesh_->GetNumDofs(), 1); | 
					 | 
					 | 
					            F_ = SpMat(sp_mesh_->GetNumDofs(), 1); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            K_ = SpMat(sp_mesh_->GetNumDofs(), sp_mesh_->GetNumDofs()); | 
					 | 
					 | 
					            K_ = SpMat(sp_mesh_->GetNumDofs(), sp_mesh_->GetNumDofs()); | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					            spdlog::info("sizeof K: {}",K_.rows()); | 
					 | 
					 | 
					            spdlog::info("DOF: {}", K_.rows()); | 
				
			
			
				
				
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					            spdlog::info("start to precompute..."); | 
					 | 
					 | 
					            spdlog::info("start to precompute..."); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            Precompute(); | 
					 | 
					 | 
					            Precompute(); | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -63,91 +63,7 @@ namespace top { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        void TopOptMainLoop() { | 
					 | 
					 | 
					        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); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                } | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					                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); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					    private: | 
					 | 
					 | 
					    private: | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
	
		
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
					@ -158,59 +74,7 @@ namespace top { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					            } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					        } | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					
					 | 
					 | 
					        void Precompute() { | 
					 | 
					 | 
					        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(); | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            } | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        } | 
					 | 
					 | 
					 | 
				
			
			
		
	
		
		
	
		
		
			
				
					 | 
					 | 
					
 | 
					 | 
					 | 
					
 | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					        int GetDof(int node_id, int dir) { | 
					 | 
					 | 
					        int GetDof(int node_id, int dir) { | 
				
			
			
		
	
		
		
			
				
					 | 
					 | 
					            return node_id * 3 + dir; | 
					 | 
					 | 
					            return node_id * 3 + dir; | 
				
			
			
		
	
	
		
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
					
  |