commit
f5238669fa
20 changed files with 69763 additions and 0 deletions
@ -0,0 +1,8 @@ |
|||||
|
# vscode |
||||
|
.vscode |
||||
|
|
||||
|
# compile |
||||
|
build |
||||
|
|
||||
|
# output |
||||
|
output |
@ -0,0 +1,26 @@ |
|||||
|
cmake_minimum_required(VERSION 3.9) |
||||
|
project(fem3d) |
||||
|
|
||||
|
# project source files |
||||
|
file(GLOB SRCFILES |
||||
|
"src/*.cpp" |
||||
|
"src/LinSysSolver/*.cpp" |
||||
|
) |
||||
|
|
||||
|
FOREACH(item ${SRCFILES}) |
||||
|
IF(${item} MATCHES "main.cpp") |
||||
|
LIST(REMOVE_ITEM SRCFILES ${item}) |
||||
|
ENDIF(${item} MATCHES "main.cpp") |
||||
|
ENDFOREACH(item) |
||||
|
|
||||
|
add_library(${PROJECT_NAME}_dev ${SRCFILES}) |
||||
|
|
||||
|
target_include_directories(${PROJECT_NAME}_dev PUBLIC |
||||
|
"src" |
||||
|
"src/LinSysSolver" |
||||
|
) |
||||
|
|
||||
|
add_executable(${PROJECT_NAME}_bin "src/main.cpp") |
||||
|
target_link_libraries(${PROJECT_NAME}_bin PUBLIC ${PROJECT_NAME}_dev) |
||||
|
# add path of Eigen header file to include directories |
||||
|
target_include_directories(${PROJECT_NAME}_dev PUBLIC "/usr/local/include/eigen-3.4.0") |
@ -0,0 +1,35 @@ |
|||||
|
# Readme |
||||
|
|
||||
|
### 1. 依赖 |
||||
|
|
||||
|
* `Eigen` |
||||
|
|
||||
|
### 2. 运行 |
||||
|
|
||||
|
```shell |
||||
|
mkdir build |
||||
|
cd build |
||||
|
cmake .. |
||||
|
make |
||||
|
``` |
||||
|
|
||||
|
* `Eigen`: 运行前,需要先在`CMakeLists.txt`的第26行修改`Eigen`的目录路径 |
||||
|
* 模型的杨氏模量、泊松比、热膨胀系数、参考温度`Tref`:通过`src/Mesh.cpp`的17~20行分别设定 |
||||
|
* 固定点`DBC`:通过修改`src/Mesh.cpp`的`setDBC`函数设定 |
||||
|
|
||||
|
### 3. 输入 |
||||
|
|
||||
|
* `input/cube.txt`:自定义格式,四面体网格信息; |
||||
|
|
||||
|
第一、二行分别是顶点数量`n`与四面体单元数量`m`, |
||||
|
|
||||
|
从第三行开始是`n`行顶点坐标与`m`行四面体顶点下标,下标从1开始 |
||||
|
|
||||
|
* `input/cube_T.txt`:热传导仿真结果,`n`行温度数值,单位开尔文(K) |
||||
|
|
||||
|
### 4. 输出 |
||||
|
|
||||
|
* `output/U.txt`:四面体网格每个顶点的位移, |
||||
|
|
||||
|
`n*3`行,第$3i-2$,$3i-1$,$3i$行表示第$i$个节点在$x$,$y$,$z$轴上的位移,$1 \leq i \leq n$ |
||||
|
|
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,77 @@ |
|||||
|
//
|
||||
|
// EigenLibSolver.cpp
|
||||
|
//
|
||||
|
// Created by Wei Chen on 9/2/21
|
||||
|
//
|
||||
|
|
||||
|
#include "EigenLibSolver.hpp" |
||||
|
|
||||
|
namespace fem3d{ |
||||
|
|
||||
|
void EigenLibSolver::set_pattern(const std::vector<std::set<int>>& vNeighbor){ |
||||
|
Base::set_pattern(vNeighbor); |
||||
|
|
||||
|
coefMtr.resize(Base::numRows, Base::numRows); |
||||
|
coefMtr.reserve(Base::nnz); |
||||
|
|
||||
|
memcpy(coefMtr.innerIndexPtr(), Base::ja.data(), Base::ja.size()*sizeof(Base::ja[0])); |
||||
|
memcpy(coefMtr.outerIndexPtr(), Base::ia.data(), Base::ia.size()*sizeof(Base::ia[0])); |
||||
|
} |
||||
|
|
||||
|
void EigenLibSolver::analyze_pattern(void){ |
||||
|
simplicialLDLT.analyzePattern(coefMtr); |
||||
|
assert(simplicialLDLT.info() == Eigen::Success); |
||||
|
} |
||||
|
|
||||
|
void EigenLibSolver::factorize(void){ |
||||
|
simplicialLDLT.factorize(coefMtr); |
||||
|
assert(simplicialLDLT.info() == Eigen::Success); |
||||
|
} |
||||
|
|
||||
|
void EigenLibSolver::solve(const Eigen::VectorXd& rhs, Eigen::VectorXd& res){ |
||||
|
res = simplicialLDLT.solve(rhs); |
||||
|
assert(simplicialLDLT.info() == Eigen::Success); |
||||
|
} |
||||
|
|
||||
|
void EigenLibSolver::setCoeff(int rowI, int colI, double val){ |
||||
|
assert(rowI < Base::numRows); |
||||
|
const auto finder = Base::IJ2aI[rowI].find(colI); |
||||
|
assert(finder != Base::IJ2aI[rowI].end()); |
||||
|
Base::a[finder->second] = val; |
||||
|
coefMtr.valuePtr()[finder->second] = val; |
||||
|
} |
||||
|
|
||||
|
void EigenLibSolver::addCoeff(int rowI, int colI, double val){ |
||||
|
assert(rowI < Base::numRows); |
||||
|
const auto finder = Base::IJ2aI[rowI].find(colI); |
||||
|
assert(finder != Base::IJ2aI[rowI].end()); |
||||
|
Base::a[finder->second] += val; |
||||
|
coefMtr.valuePtr()[finder->second] += val; |
||||
|
} |
||||
|
|
||||
|
void EigenLibSolver::setZero(void){ |
||||
|
Base::setZero(); |
||||
|
memcpy(coefMtr.valuePtr(), Base::a.data(), Base::a.size()*sizeof(Base::a[0])); |
||||
|
} |
||||
|
|
||||
|
void EigenLibSolver::setUnitRow(int rowI){ |
||||
|
assert(rowI < Base::numRows); |
||||
|
for(const auto& colI : Base::IJ2aI[rowI]){ |
||||
|
double tmp = (rowI == colI.first); |
||||
|
Base::a[colI.second] = tmp; |
||||
|
coefMtr.valuePtr()[colI.second] = tmp; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void EigenLibSolver::setZeroCol(int colI){ |
||||
|
assert(colI < Base::numRows); |
||||
|
for(int rowI=0; rowI<Base::numRows; ++rowI){ |
||||
|
const auto finder = Base::IJ2aI[rowI].find(colI); |
||||
|
if(finder != Base::IJ2aI[rowI].end()){ |
||||
|
Base::a[finder->second] = 0.0; |
||||
|
coefMtr.valuePtr()[finder->second] = 0.0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // namespace
|
@ -0,0 +1,37 @@ |
|||||
|
//
|
||||
|
// EigenLibSolver.hpp
|
||||
|
//
|
||||
|
// Created by Wei Chen on 9/2/21
|
||||
|
//
|
||||
|
|
||||
|
#ifndef EigenLibSolver_hpp |
||||
|
#define EigenLibSolver_hpp |
||||
|
|
||||
|
#include "LinSysSolver.hpp" |
||||
|
|
||||
|
namespace fem3d{ |
||||
|
|
||||
|
class EigenLibSolver : public LinSysSolver{ |
||||
|
typedef LinSysSolver Base; |
||||
|
|
||||
|
protected: |
||||
|
Eigen::SparseMatrix<double> coefMtr; |
||||
|
Eigen::SimplicialLDLT<Eigen::SparseMatrix<double>> simplicialLDLT; |
||||
|
|
||||
|
public: |
||||
|
virtual void set_pattern(const std::vector<std::set<int>>& vNeighbor); |
||||
|
|
||||
|
virtual void analyze_pattern(void); |
||||
|
virtual void factorize(void); |
||||
|
virtual void solve(const Eigen::VectorXd& rhs, Eigen::VectorXd& res); |
||||
|
|
||||
|
virtual void setCoeff(int rowI, int colI, double val); |
||||
|
virtual void addCoeff(int rowI, int colI, double val); |
||||
|
virtual void setZero(void); |
||||
|
virtual void setUnitRow(int rowI); |
||||
|
virtual void setZeroCol(int colI); |
||||
|
}; |
||||
|
|
||||
|
} // namespace
|
||||
|
|
||||
|
#endif // EigenLibSolver_hpp
|
@ -0,0 +1,113 @@ |
|||||
|
//
|
||||
|
// LinSysSolver.hpp
|
||||
|
//
|
||||
|
// Created by Wei Chen on 9/2/21
|
||||
|
//
|
||||
|
|
||||
|
#ifndef LinSysSolver_hpp |
||||
|
#define LinSysSolver_hpp |
||||
|
|
||||
|
#include <Eigen/Eigen> |
||||
|
#include <iostream> |
||||
|
#include <set> |
||||
|
#include <map> |
||||
|
#include <vector> |
||||
|
|
||||
|
namespace fem3d{ |
||||
|
|
||||
|
class LinSysSolver{ |
||||
|
protected: |
||||
|
int numRows, nnz; |
||||
|
Eigen::VectorXi ia, ja; |
||||
|
std::vector<std::map<int, int>> IJ2aI; |
||||
|
Eigen::VectorXd a; |
||||
|
|
||||
|
public: |
||||
|
virtual ~LinSysSolver(void){}; |
||||
|
|
||||
|
virtual void set_pattern(const std::vector<std::set<int>>& vNeighbor){ |
||||
|
int nvet = static_cast<int>(vNeighbor.size()); |
||||
|
numRows = nvet * 3; |
||||
|
nnz = 0; |
||||
|
for(int vI=0; vI<nvet; ++vI){ |
||||
|
nnz += static_cast<int>(vNeighbor[vI].size()) * 9; |
||||
|
} |
||||
|
|
||||
|
ia.setZero(numRows+1); |
||||
|
ja.setZero(nnz); |
||||
|
IJ2aI.resize(0); |
||||
|
IJ2aI.resize(numRows); |
||||
|
a.setZero(nnz); |
||||
|
|
||||
|
for(int vI=0; vI<nvet; ++vI){ |
||||
|
int num = static_cast<int>(vNeighbor[vI].size()) * 3; |
||||
|
for(int dof=0; dof<3; ++dof){ |
||||
|
int row = vI * 3 + dof; |
||||
|
ia(row+1) = ia(row) + num; |
||||
|
int cnt = 0; |
||||
|
for(const auto& nbVI : vNeighbor[vI]){ |
||||
|
ja(ia(row)+cnt) = nbVI * 3; |
||||
|
ja(ia(row)+cnt+1) = nbVI * 3 + 1; |
||||
|
ja(ia(row)+cnt+2) = nbVI * 3 + 2; |
||||
|
IJ2aI[row][nbVI*3] = ia(row) + cnt; |
||||
|
IJ2aI[row][nbVI*3+1] = ia(row) + cnt + 1; |
||||
|
IJ2aI[row][nbVI*3+2] = ia(row) + cnt + 2; |
||||
|
cnt += 3; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual void analyze_pattern(void) = 0; |
||||
|
virtual void factorize(void) = 0; |
||||
|
virtual void solve(const Eigen::VectorXd& rhs, Eigen::VectorXd& res) = 0; |
||||
|
|
||||
|
virtual void setCoeff(int rowI, int colI, double val){ |
||||
|
assert(rowI<numRows); |
||||
|
const auto finder = IJ2aI[rowI].find(colI); |
||||
|
assert(finder!=IJ2aI[rowI].end()); |
||||
|
a[finder->second] = val; |
||||
|
} |
||||
|
|
||||
|
virtual void addCoeff(int rowI, int colI, double val){ |
||||
|
assert(rowI<numRows); |
||||
|
const auto finder = IJ2aI[rowI].find(colI); |
||||
|
assert(finder!=IJ2aI[rowI].end()); |
||||
|
a[finder->second] += val; |
||||
|
} |
||||
|
|
||||
|
virtual void setZero(void){ |
||||
|
a.setZero(); |
||||
|
} |
||||
|
|
||||
|
virtual void multiply(const Eigen::VectorXd& x, Eigen::VectorXd& Ax){ |
||||
|
assert(x.size()==numRows); |
||||
|
Ax.setZero(numRows); |
||||
|
for(int rowI=0; rowI<numRows; ++rowI){ |
||||
|
for(const auto& colI : IJ2aI[rowI]){ |
||||
|
Ax(rowI) += a[colI.second] * x(colI.first); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual void setUnitRow(int rowI){ |
||||
|
assert(rowI<numRows); |
||||
|
for(const auto& colI : IJ2aI[rowI]){ |
||||
|
a[colI.second] = (rowI==colI.first); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
virtual void setZeroCol(int colI){ |
||||
|
assert(colI<numRows); |
||||
|
for(int rowI=0; rowI<numRows; ++rowI){ |
||||
|
const auto finder = IJ2aI[rowI].find(colI); |
||||
|
if(finder != IJ2aI[rowI].end()){ |
||||
|
a[finder->second] = 0.0; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
} // namespace
|
||||
|
|
||||
|
#endif // LinSysSolver_hpp
|
@ -0,0 +1,223 @@ |
|||||
|
//
|
||||
|
// Mesh.cpp
|
||||
|
//
|
||||
|
// Created by Wei Chen on 9/1/21
|
||||
|
//
|
||||
|
|
||||
|
#include "Mesh.hpp" |
||||
|
#include "Utils.hpp" |
||||
|
|
||||
|
#include <iostream> |
||||
|
#include <cmath> |
||||
|
#include <cstdlib> |
||||
|
|
||||
|
namespace fem3d{ |
||||
|
|
||||
|
Mesh::Mesh(void){ |
||||
|
E = 73.0; |
||||
|
nu = 0.17; |
||||
|
alpha = 5.5e-7; |
||||
|
Tref = 293.15; |
||||
|
D.resize(6, 6); |
||||
|
D << 1.0-nu, nu, nu, 0.0, 0.0, 0.0, |
||||
|
nu, 1.0-nu, nu, 0.0, 0.0, 0.0, |
||||
|
nu, nu, 1.0-nu, 0.0, 0.0, 0.0, |
||||
|
0.0, 0.0, 0.0, (1.0-2.0*nu)/2.0, 0.0, 0.0, |
||||
|
0.0, 0.0, 0.0, 0.0, (1.0-2.0*nu)/2.0, 0.0, |
||||
|
0.0, 0.0, 0.0, 0.0, 0.0, (1.0-2.0*nu)/2.0; |
||||
|
double tmp = E / (1.0 + nu) / (1.0 - 2.0 * nu); |
||||
|
D = D * tmp; |
||||
|
|
||||
|
if(!Utils::readMesh("../input/cube.txt", nvet, nele, vet, ele)){ |
||||
|
std::cout << "Logging: [fem3d] error on reading vertices" << std::endl; |
||||
|
exit(-1); |
||||
|
} |
||||
|
T.resize(nvet); |
||||
|
if(!Utils::readTemp("../input/cube_T.txt", T)){ |
||||
|
std::cout << "Logging: [fem3d] error on reading temperature" << std::endl; |
||||
|
exit(-1); |
||||
|
} |
||||
|
T = alpha * (T - Eigen::VectorXd::Constant(nvet, Tref)); |
||||
|
ndof = nvet * 3; |
||||
|
|
||||
|
F.setZero(ndof); |
||||
|
U.setZero(ndof); |
||||
|
|
||||
|
computeFeatures(); |
||||
|
linSysSolver = new EigenLibSolver(); |
||||
|
linSysSolver->set_pattern(vNeighbor); |
||||
|
linSysSolver->analyze_pattern(); |
||||
|
std::cout << "Logging: [fem3d] mesh constructed" << std::endl; |
||||
|
} |
||||
|
|
||||
|
Mesh::~Mesh(void){ |
||||
|
delete linSysSolver; |
||||
|
} |
||||
|
|
||||
|
void Mesh::computeFeatures(void){ // compute vNeighbor
|
||||
|
vNeighbor.resize(0); |
||||
|
vNeighbor.resize(nvet); |
||||
|
|
||||
|
for(int vI=0; vI<nvet; ++vI){ |
||||
|
vNeighbor[vI].insert(vI); |
||||
|
} |
||||
|
|
||||
|
for(int eleI=0; eleI<nele; ++eleI){ |
||||
|
const Eigen::Matrix<int, 1, 4>& eleVInd = ele.row(eleI); |
||||
|
for(int i=0; i<4; ++i){ |
||||
|
for(int j=i+1; j<4; ++j){ |
||||
|
vNeighbor[eleVInd(i)].insert(eleVInd(j)); |
||||
|
vNeighbor[eleVInd(j)].insert(eleVInd(i)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Mesh::computeK(void){ // assembly stiffness matrix K and load F
|
||||
|
linSysSolver->setZero(); |
||||
|
|
||||
|
for(int eleI=0; eleI<nele; ++eleI){ |
||||
|
const Eigen::Matrix<int, 1, 4>& eleVInd = ele.row(eleI); |
||||
|
Eigen::Matrix<double, 4, 3> Xe; |
||||
|
Xe.row(0) = vet.row(eleVInd(0)); |
||||
|
Xe.row(1) = vet.row(eleVInd(1)); |
||||
|
Xe.row(2) = vet.row(eleVInd(2)); |
||||
|
Xe.row(3) = vet.row(eleVInd(3)); |
||||
|
double Te = (T(eleVInd(0)) + T(eleVInd(1)) + T(eleVInd(2)) + |
||||
|
T(eleVInd(3))) / 4.0; |
||||
|
|
||||
|
int num = 12; |
||||
|
Eigen::MatrixXd Ke(num, num); |
||||
|
Eigen::VectorXd Fe(num); |
||||
|
computeKe(Xe, Te, Ke, Fe); |
||||
|
|
||||
|
Eigen::VectorXi edof(num); |
||||
|
edof << eleVInd(0)*3, eleVInd(0)*3+1, eleVInd(0)*3+2, |
||||
|
eleVInd(1)*3, eleVInd(1)*3+1, eleVInd(1)*3+2, |
||||
|
eleVInd(2)*3, eleVInd(2)*3+1, eleVInd(2)*3+2, |
||||
|
eleVInd(3)*3, eleVInd(3)*3+1, eleVInd(3)*3+2; |
||||
|
|
||||
|
for(int i=0; i<num; ++i){ // assembly K
|
||||
|
for(int j=0; j<num; ++j){ |
||||
|
linSysSolver->addCoeff(edof(i), edof(j), Ke(i, j)); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
for(int i=0; i<num; ++i){ // assembly F
|
||||
|
F(edof(i)) += Fe(i); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// compute element stiffness matrix
|
||||
|
void Mesh::computeKe(const Eigen::Matrix<double, 4, 3>& X, double T, |
||||
|
Eigen::MatrixXd& Ke, Eigen::VectorXd& Fe){ |
||||
|
Eigen::MatrixXd H(4, 4); |
||||
|
H << 1.0, X(0, 0), X(0, 1), X(0, 2), |
||||
|
1.0, X(1, 0), X(1, 1), X(1, 2), |
||||
|
1.0, X(2, 0), X(2, 1), X(2, 2), |
||||
|
1.0, X(3, 0), X(3, 1), X(3, 2); |
||||
|
double V6 = H.determinant(); |
||||
|
|
||||
|
Eigen::VectorXi rowInd(3); |
||||
|
Eigen::VectorXi colInd(3); |
||||
|
Eigen::MatrixXd sub(3, 3); |
||||
|
|
||||
|
colInd << 0, 2, 3; |
||||
|
rowInd << 1, 2, 3; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double b1 = -sub.determinant(); |
||||
|
rowInd << 0, 2, 3; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double b2 = sub.determinant(); |
||||
|
rowInd << 0, 1, 3; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double b3 = -sub.determinant(); |
||||
|
rowInd << 0, 1, 2; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double b4 = sub.determinant(); |
||||
|
|
||||
|
colInd << 0, 1, 3; |
||||
|
rowInd << 1, 2, 3; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double c1 = sub.determinant(); |
||||
|
rowInd << 0, 2, 3; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double c2 = -sub.determinant(); |
||||
|
rowInd << 0, 1, 3; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double c3 = sub.determinant(); |
||||
|
rowInd << 0, 1, 2; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double c4 = -sub.determinant(); |
||||
|
|
||||
|
|
||||
|
colInd << 0, 1, 2; |
||||
|
rowInd << 1, 2, 3; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double d1 = -sub.determinant(); |
||||
|
rowInd << 0, 2, 3; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double d2 = sub.determinant(); |
||||
|
rowInd << 0, 1, 3; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double d3 = -sub.determinant(); |
||||
|
rowInd << 0, 1, 2; |
||||
|
Utils::subMatrix(H, rowInd, colInd, sub); |
||||
|
double d4 = sub.determinant(); |
||||
|
|
||||
|
Eigen::MatrixXd B(6, 12); |
||||
|
B << b1, 0, 0, b2, 0, 0, b3, 0, 0, b4, 0, 0, |
||||
|
0, c1, 0, 0, c2, 0, 0, c3, 0, 0, c4, 0, |
||||
|
0, 0, d1, 0, 0, d2, 0, 0, d3, 0, 0, d4, |
||||
|
c1, b1, 0, c2, b2, 0, c3, b3, 0, c4, b4, 0, |
||||
|
0, d1, c1, 0, d2, c2, 0, d3, c3, 0, d4, c4, |
||||
|
d1, 0, b1, d2, 0, b2, d3, 0, b3, d4, 0, b4; |
||||
|
B = B / V6; |
||||
|
|
||||
|
Ke = V6 / 6.0 * (B.transpose() * D * B); |
||||
|
|
||||
|
Eigen::VectorXd strain(6); |
||||
|
strain << T, T, T, 0.0, 0.0, 0.0; |
||||
|
Fe = V6 / 6.0 * (B.transpose() * D * strain); |
||||
|
} |
||||
|
|
||||
|
void Mesh::boundaryK(void){ |
||||
|
for(int i=0; i<DBCV.size(); ++i){ |
||||
|
int DBCI = DBCV(i); |
||||
|
linSysSolver->setZeroCol(DBCI); |
||||
|
linSysSolver->setUnitRow(DBCI); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Mesh::solve(void){ |
||||
|
linSysSolver->factorize(); |
||||
|
linSysSolver->solve(F, U); |
||||
|
|
||||
|
for(int i=0; i<DBCV.size(); ++i){ // boundary DBC dofs
|
||||
|
U(DBCV(i)) = 0.0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void Mesh::write(void){ |
||||
|
if(!Utils::writeU("../output/U.txt", U)){ |
||||
|
std::cout << "Logging: [fem3d] error on writing displacement U" << std::endl; |
||||
|
exit(-1); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// <<< interfaces
|
||||
|
void Mesh::setDBC(void){ // user defined fixed dofs
|
||||
|
DBCV.resize(0); |
||||
|
for(int vI=0; vI<nvet; ++vI){ |
||||
|
if(abs(vet(vI, 2))<eps){ |
||||
|
DBCV.conservativeResize(DBCV.size()+3); |
||||
|
DBCV(DBCV.size()-3) = vI * 3; |
||||
|
DBCV(DBCV.size()-2) = vI * 3 + 1; |
||||
|
DBCV(DBCV.size()-1) = vI * 3 + 2; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
// >>> interfaces
|
||||
|
|
||||
|
} // namespace
|
@ -0,0 +1,55 @@ |
|||||
|
//
|
||||
|
// Mesh.hpp
|
||||
|
//
|
||||
|
// Created by Wei Chen on 9/1/21
|
||||
|
//
|
||||
|
|
||||
|
#ifndef Mesh_hpp |
||||
|
#define Mesh_hpp |
||||
|
|
||||
|
#include "EigenLibSolver.hpp" |
||||
|
|
||||
|
#include <Eigen/Eigen> |
||||
|
#include <vector> |
||||
|
#include <set> |
||||
|
|
||||
|
namespace fem3d{ |
||||
|
|
||||
|
class Mesh{ |
||||
|
public: // owned data
|
||||
|
int nvet, nele, ndof; |
||||
|
Eigen::MatrixXd vet; // vertices coordinates
|
||||
|
Eigen::MatrixXi ele; // vertice index of each tetrahedron
|
||||
|
Eigen::VectorXd T; // temperatrue of each vertice
|
||||
|
double E, nu; |
||||
|
double alpha, Tref; |
||||
|
Eigen::MatrixXd D; // constitutive matrix
|
||||
|
|
||||
|
public: // owned features
|
||||
|
double eps = 1e-8; |
||||
|
Eigen::VectorXd F; // load of each dof
|
||||
|
Eigen::VectorXd U; // dofs' displacement to be computed
|
||||
|
Eigen::VectorXi DBCV; // dofs in DBC
|
||||
|
std::vector<std::set<int>> vNeighbor; // records all vertices' indices adjacent to each vertice
|
||||
|
LinSysSolver* linSysSolver; |
||||
|
|
||||
|
public: // constructor
|
||||
|
Mesh(void); |
||||
|
~Mesh(void); |
||||
|
|
||||
|
public: |
||||
|
void computeFeatures(void); |
||||
|
void computeK(void); |
||||
|
void computeKe(const Eigen::Matrix<double, 4, 3>& X, double T, |
||||
|
Eigen::MatrixXd& Ke, Eigen::VectorXd& Fe); |
||||
|
void boundaryK(void); |
||||
|
void solve(void); |
||||
|
void write(void); |
||||
|
|
||||
|
public: // interface: set load and DBC
|
||||
|
void setDBC(void); |
||||
|
}; |
||||
|
|
||||
|
} // namespace
|
||||
|
|
||||
|
#endif // Mesh_hpp
|
@ -0,0 +1,72 @@ |
|||||
|
//
|
||||
|
// Utils.cpp
|
||||
|
//
|
||||
|
// Created by Wei Chen on 9/1/21
|
||||
|
//
|
||||
|
|
||||
|
#include "Utils.hpp" |
||||
|
|
||||
|
namespace fem3d{ |
||||
|
|
||||
|
bool Utils::readMesh(const std::string& filePath, int& nvet, int& nele, |
||||
|
Eigen::MatrixXd& vet, Eigen::MatrixXi& ele){ |
||||
|
FILE* in = fopen(filePath.c_str(), "r"); |
||||
|
if(!in){ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
fscanf(in, "%d%d", &nvet, &nele); |
||||
|
vet.resize(nvet, 3); |
||||
|
ele.resize(nele, 4); |
||||
|
|
||||
|
for(int vI=0; vI<nvet; ++vI){ |
||||
|
fscanf(in, "%lf%lf%lf", &vet(vI, 0), &vet(vI, 1), &vet(vI, 2)); |
||||
|
} |
||||
|
for(int eleI=0; eleI<nele; ++eleI){ |
||||
|
fscanf(in, "%d%d%d%d", &ele(eleI, 0), &ele(eleI, 1), &ele(eleI, 2), &ele(eleI, 3)); |
||||
|
} |
||||
|
ele.array() -= 1; |
||||
|
|
||||
|
fclose(in); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool Utils::readTemp(const std::string& filePath, Eigen::VectorXd& T){ |
||||
|
FILE* in = fopen(filePath.c_str(), "r"); |
||||
|
if(!in){ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
for(int vI=0; vI<T.size(); ++vI){ |
||||
|
fscanf(in, "%lf", &T(vI)); |
||||
|
} |
||||
|
|
||||
|
fclose(in); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
bool Utils::writeU(const std::string& filePath, const Eigen::VectorXd& U){ |
||||
|
FILE* out = fopen(filePath.c_str(), "w"); |
||||
|
if(!out){ |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
for(int i=0; i<U.size(); ++i){ |
||||
|
fprintf(out, "%le\n", U(i)); |
||||
|
} |
||||
|
|
||||
|
fclose(out); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
// return sub-matrix(3*3) of H(4*4)
|
||||
|
void Utils::subMatrix(const Eigen::MatrixXd& H, const Eigen::VectorXi& rowInd, |
||||
|
const Eigen::VectorXi& colInd, Eigen::MatrixXd& sub){ |
||||
|
for(int i=0; i<3; ++i){ |
||||
|
for(int j=0; j<3; ++j){ |
||||
|
sub(i, j) = H(rowInd(i), colInd(j)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} // namespace
|
@ -0,0 +1,29 @@ |
|||||
|
//
|
||||
|
// Utils.hpp
|
||||
|
//
|
||||
|
// Created by Wei Chen on 9/1/21
|
||||
|
//
|
||||
|
|
||||
|
#ifndef Utils_hpp |
||||
|
#define Utils_hpp |
||||
|
|
||||
|
#include <Eigen/Eigen> |
||||
|
#include <iostream> |
||||
|
#include <fstream> |
||||
|
|
||||
|
namespace fem3d{ |
||||
|
|
||||
|
// a static class implementing some assitant functions
|
||||
|
class Utils{ |
||||
|
public: |
||||
|
static bool readMesh(const std::string& filePath, int& nvet, int& nele, |
||||
|
Eigen::MatrixXd& vet, Eigen::MatrixXi& ele); |
||||
|
static bool readTemp(const std::string& filePath, Eigen::VectorXd& T); |
||||
|
static bool writeU(const std::string& filePath, const Eigen::VectorXd& U); |
||||
|
static void subMatrix(const Eigen::MatrixXd& H, const Eigen::VectorXi& rowInd, |
||||
|
const Eigen::VectorXi& colInd, Eigen::MatrixXd& sub); |
||||
|
}; |
||||
|
|
||||
|
} // namespace
|
||||
|
|
||||
|
#endif // Utils_hpp
|
@ -0,0 +1,26 @@ |
|||||
|
//
|
||||
|
// main.cpp
|
||||
|
//
|
||||
|
// Created by Wei Chen on 8/30/21
|
||||
|
//
|
||||
|
|
||||
|
#include "Mesh.hpp" |
||||
|
|
||||
|
#include <Eigen/Eigen> |
||||
|
#include <iostream> |
||||
|
|
||||
|
int main(){ |
||||
|
fem3d::Mesh mesh = fem3d::Mesh(); |
||||
|
mesh.setDBC(); |
||||
|
std::cout << "Logging: [fem3d] set DBC" << std::endl; |
||||
|
|
||||
|
mesh.computeK(); |
||||
|
std::cout << "Logging: [fem3d] assembly stiffness matrix and load" << std::endl; |
||||
|
mesh.boundaryK(); |
||||
|
|
||||
|
mesh.solve(); |
||||
|
std::cout << "Logging: [fem3d] solve" << std::endl; |
||||
|
mesh.write(); |
||||
|
std::cout << "Logging: [fem3d] write displacement to output/U.txt" << std::endl; |
||||
|
return 0; |
||||
|
} |
@ -0,0 +1,152 @@ |
|||||
|
% |
||||
|
% fem3d_tet_linear.m |
||||
|
% |
||||
|
% Created by Wei Chen on 8/4/21 |
||||
|
% |
||||
|
|
||||
|
function fem3d_tet_linear() |
||||
|
nvet = 3168; % nvet: number of vertices, nele: number of elements |
||||
|
nele = 16563; |
||||
|
|
||||
|
disp('fem simulation start') |
||||
|
|
||||
|
eeps = 1e-8; |
||||
|
% USER-DEFINED MATERIAL PROPERTIES |
||||
|
E = 73.0; % Young's modulus of solid material |
||||
|
nu = 0.17; % Poisson's ratio |
||||
|
alpha = 5.5e-7; |
||||
|
Tref = 293.15; |
||||
|
% constitutive matrix |
||||
|
D = E / (1 + nu) / (1 - 2 * nu) * ... |
||||
|
[ 1-nu nu nu 0 0 0 ; |
||||
|
nu 1-nu nu 0 0 0 ; |
||||
|
nu nu 1-nu 0 0 0 ; |
||||
|
0 0 0 (1-2*nu)/2 0 0 ; |
||||
|
0 0 0 0 (1-2*nu)/2 0 ; |
||||
|
0 0 0 0 0 (1-2*nu)/2]; |
||||
|
|
||||
|
% read coordinates of vertices, tetrahedron information |
||||
|
cor = load('input/cor.txt'); |
||||
|
elem = load('input/elem.txt'); |
||||
|
T = load('input/T.txt'); |
||||
|
T = (alpha) * (T - Tref); |
||||
|
|
||||
|
% PREPARE FINITE ELEMENT ANALYSIS |
||||
|
ndof = nvet * 3; |
||||
|
U = zeros(ndof,1); |
||||
|
F = zeros(ndof,1); |
||||
|
|
||||
|
% USER-DEFINED SUPPORT FIXED DOFs |
||||
|
fixednids = find(abs(cor(:, 3)) < eeps); |
||||
|
fixeddofs = [3*fixednids-2; 3*fixednids-1; 3*fixednids]; |
||||
|
freedofs = setdiff(1:ndof,fixeddofs); |
||||
|
disp('compute DBC') |
||||
|
|
||||
|
% assembly the stiffness matrix |
||||
|
edofMat = kron(elem, 3*ones(1, 3)); |
||||
|
edofMat(:, 1:3:12) = edofMat(:, 1:3:12) - 2; |
||||
|
edofMat(:, 2:3:12) = edofMat(:, 2:3:12) - 1; |
||||
|
iK = reshape(kron(edofMat,ones(12,1))',12*12*nele,1); |
||||
|
jK = reshape(kron(edofMat,ones(1,12))',12*12*nele,1); |
||||
|
|
||||
|
sK = zeros(12*12, nele); |
||||
|
for eleI = 1:nele |
||||
|
elenids = [elem(eleI, 1), elem(eleI, 2), elem(eleI, 3), elem(eleI, 4)]; |
||||
|
eledofs = kron(elenids, 3*ones(1, 3)); |
||||
|
eledofs(1, 1:3:12) = eledofs(1, 1:3:12) - 2; |
||||
|
eledofs(1, 2:3:12) = eledofs(1, 2:3:12) - 1; |
||||
|
|
||||
|
Xe = cor(elenids, :); |
||||
|
Te = T(elenids, 1); |
||||
|
[KE, Fe] = initKE(D, Xe, Te); |
||||
|
sK(:, eleI) = KE(:); |
||||
|
F(eledofs, 1) = F(eledofs, 1) + Fe; |
||||
|
end |
||||
|
sK = reshape(sK, 12*12*nele, 1); |
||||
|
|
||||
|
% FE-ANALYSIS |
||||
|
K = sparse(iK,jK,sK); K = (K+K')/2; |
||||
|
% save K1.mat K; |
||||
|
U(freedofs,:) = K(freedofs,freedofs)\F(freedofs,:); |
||||
|
disp('solve') |
||||
|
|
||||
|
save U.mat U; |
||||
|
% display result |
||||
|
cor1 = cor + reshape(U, 3, nvet)'; |
||||
|
figure; |
||||
|
scatter3(cor1(:, 1), cor1(:, 2), cor1(:, 3)); |
||||
|
|
||||
|
disp('simulation end') |
||||
|
|
||||
|
end |
||||
|
|
||||
|
% === GENERATE ELEMENT STIFFNESS MATRIX === |
||||
|
% X: 4*3 matrix, which is corridinates of element vertices |
||||
|
function [KE, Fe] = initKE(D, Xe, Te) |
||||
|
H = ... |
||||
|
[ 1.0 Xe(1, 1) Xe(1, 2) Xe(1, 3); |
||||
|
1.0 Xe(2, 1) Xe(2, 2) Xe(2, 3); |
||||
|
1.0 Xe(3, 1) Xe(3, 2) Xe(3, 3); |
||||
|
1.0 Xe(4, 1) Xe(4, 2) Xe(4, 3)]; |
||||
|
V6 = det(H); % 6*V, V is volumn of tetrahedron element |
||||
|
|
||||
|
% a1 = det(H([2, 3, 4], [2, 3, 4])); |
||||
|
% a2 = -det(H([1, 3, 4], [2, 3, 4])); |
||||
|
% a3 = det(H([1, 2, 4], [2, 3, 4])); |
||||
|
% a4 = -det(H([1, 2, 3], [2, 3, 4])); |
||||
|
|
||||
|
b1 = -det(H([2, 3, 4], [1, 3, 4])); |
||||
|
b2 = det(H([1, 3, 4], [1, 3, 4])); |
||||
|
b3 = -det(H([1, 2, 4], [1, 3, 4])); |
||||
|
b4 = det(H([1, 2, 3], [1, 3, 4])); |
||||
|
|
||||
|
c1 = det(H([2, 3, 4], [1, 2, 4])); |
||||
|
c2 = -det(H([1, 3, 4], [1, 2, 4])); |
||||
|
c3 = det(H([1, 2, 4], [1, 2, 4])); |
||||
|
c4 = -det(H([1, 2, 3], [1, 2, 4])); |
||||
|
|
||||
|
d1 = -det(H([2, 3, 4], [1, 2, 3])); |
||||
|
d2 = det(H([1, 3, 4], [1, 2, 3])); |
||||
|
d3 = -det(H([1, 2, 4], [1, 2, 3])); |
||||
|
d4 = det(H([1, 2, 3], [1, 2, 3])); |
||||
|
|
||||
|
B = zeros(6, 12); |
||||
|
|
||||
|
B(:, 1:3) = ... |
||||
|
[ b1 0 0; |
||||
|
0 c1 0; |
||||
|
0 0 d1; |
||||
|
c1 b1 0; |
||||
|
0 d1 c1; |
||||
|
d1 0 b1]; |
||||
|
|
||||
|
B(:, 4:6) = ... |
||||
|
[ b2 0 0; |
||||
|
0 c2 0; |
||||
|
0 0 d2; |
||||
|
c2 b2 0; |
||||
|
0 d2 c2; |
||||
|
d2 0 b2]; |
||||
|
|
||||
|
B(:, 7:9) = ... |
||||
|
[ b3 0 0; |
||||
|
0 c3 0; |
||||
|
0 0 d3; |
||||
|
c3 b3 0; |
||||
|
0 d3 c3; |
||||
|
d3 0 b3]; |
||||
|
|
||||
|
B(:, 10:12) = ... |
||||
|
[ b4 0 0; |
||||
|
0 c4 0; |
||||
|
0 0 d4; |
||||
|
c4 b4 0; |
||||
|
0 d4 c4; |
||||
|
d4 0 b4]; |
||||
|
|
||||
|
B = B / V6; |
||||
|
KE = V6 / 6.0 * (B' * D * B); |
||||
|
|
||||
|
strain = mean(Te) * [1; 1; 1; 0; 0; 0]; |
||||
|
Fe = V6 / 6.0 * (B' * D * strain); |
||||
|
end |
File diff suppressed because it is too large
File diff suppressed because it is too large
File diff suppressed because it is too large
@ -0,0 +1,209 @@ |
|||||
|
# |
||||
|
# fem3d_tet_linear.py |
||||
|
# |
||||
|
# Created by Wei Chen on 8/12/21 |
||||
|
# |
||||
|
|
||||
|
import numpy as np |
||||
|
from scipy.sparse import coo_matrix |
||||
|
from scipy.sparse.linalg import spsolve |
||||
|
import math |
||||
|
|
||||
|
''' |
||||
|
fem3d_tet_linear: linear fem of 3d tetrahedron model |
||||
|
@input: |
||||
|
nvet: number of vertices |
||||
|
nele: number of tetrahedron |
||||
|
input/cor.txt: corrdinates of vertices |
||||
|
input/elem.txt: indices of tetrahedron elements |
||||
|
@output: |
||||
|
output/u.txt: displacement of vertices |
||||
|
output/cor1.txt: result corrdinates of vertices |
||||
|
''' |
||||
|
def fem3d_tet_linear(): |
||||
|
print('fem simulation start') |
||||
|
|
||||
|
eeps = 1e-8 |
||||
|
# user-defined material properities |
||||
|
E = 73.0 # Young's modulus |
||||
|
nu = 0.17 # Poisson's ratio |
||||
|
alpha = 5.5e-7 |
||||
|
Tref = 293.15 |
||||
|
# constitutive matrix |
||||
|
D = E / (1. + nu) / (1. - 2. * nu) * np.array( |
||||
|
[[1-nu, nu, nu, 0., 0., 0.], |
||||
|
[nu, 1-nu, nu, 0., 0., 0.], |
||||
|
[nu, nu, 1-nu, 0., 0., 0.], |
||||
|
[0., 0., 0., (1.0-2.0*nu)/2.0, 0., 0.], |
||||
|
[0., 0., 0., 0., (1.0-2.0*nu)/2.0, 0.], |
||||
|
[0., 0., 0., 0., 0., (1.0-2.0*nu)/2.0]], dtype=np.float64) |
||||
|
|
||||
|
# read coordinates of vertices, tetrahedron information |
||||
|
nvet, nele, cor, elem = readTet('input/cube.txt') |
||||
|
T = readT(nvet, 'input/cube_T.txt') |
||||
|
T = alpha * (T - Tref) |
||||
|
|
||||
|
# prepare finite element analysis |
||||
|
ndof = nvet * 3 |
||||
|
U = np.zeros((ndof), dtype=np.float64) |
||||
|
F = np.zeros((ndof), dtype=np.float64) |
||||
|
|
||||
|
# user-defined fixed dofs |
||||
|
fixednids = np.asarray(cor[:, 2]==0.0).nonzero()[0] |
||||
|
fixeddofs = np.concatenate((fixednids*3, fixednids*3+1, fixednids*3+2), axis=0) |
||||
|
freedofs = np.setdiff1d(np.arange(ndof), fixeddofs) |
||||
|
print('compute DBC') |
||||
|
|
||||
|
# assembly the stiffness matrix |
||||
|
edofMat = np.kron(3*elem, np.ones((1, 3))) + np.kron(np.tile(np.arange(3), 4), np.ones((nele, 1))) |
||||
|
edofMat = edofMat.astype(np.int32) |
||||
|
iK = np.kron(edofMat, np.ones((12, 1))).flatten() |
||||
|
jK = np.kron(edofMat, np.ones((1, 12))).flatten() |
||||
|
iK = iK.astype(np.int32) |
||||
|
jK = jK.astype(np.int32) |
||||
|
|
||||
|
sK = np.empty((nele, 12*12), dtype=np.float64) |
||||
|
for eleI in range(nele): |
||||
|
elenids = np.array([elem[eleI, 0], elem[eleI, 1], elem[eleI, 2], elem[eleI, 3]], dtype=np.int32) |
||||
|
eledofs = np.kron(3*elenids, np.ones((1, 3))) + np.tile(np.arange(3), 4) |
||||
|
eledofs = eledofs.astype(np.int32) |
||||
|
|
||||
|
Xe = cor[elenids, :] |
||||
|
Te = T[elenids] |
||||
|
KE, Fe = initKE(D, Xe, Te) |
||||
|
sK[eleI, :] = KE.flatten('F') |
||||
|
F[eledofs] = F[eledofs] + Fe |
||||
|
sK = sK.flatten() |
||||
|
|
||||
|
K = coo_matrix((sK, (iK, jK)), shape=(ndof, ndof)).tocsc() |
||||
|
|
||||
|
# FE-analysis |
||||
|
print('solve') |
||||
|
K = K[freedofs, :][:, freedofs] |
||||
|
U[freedofs] = spsolve(K, F[freedofs]) |
||||
|
|
||||
|
# write result |
||||
|
print('write displacement U.txt and new corrdinates cor1.txt') |
||||
|
with open('output/U.txt', 'w') as f: |
||||
|
for i in range(ndof): |
||||
|
print(U[i], file=f) |
||||
|
cor1 = cor + U.reshape(nvet, 3) |
||||
|
with open('output/cor1.txt', 'w') as f: |
||||
|
for vI in range(nvet): |
||||
|
print(cor1[vI, 0], cor1[vI, 1], cor1[vI, 2], file=f) |
||||
|
|
||||
|
|
||||
|
def readTet(filePath): |
||||
|
with open(filePath, 'r') as f: |
||||
|
line = f.readline() |
||||
|
line_split = line.split() |
||||
|
nvet = int(line_split[0]) |
||||
|
line = f.readline() |
||||
|
line_split = line.split() |
||||
|
nele = int(line_split[0]) |
||||
|
|
||||
|
cor = np.empty((nvet, 3), dtype=np.float64) |
||||
|
for vI in range(nvet): |
||||
|
line = f.readline() |
||||
|
line_split = line.split() |
||||
|
cor[vI, 0] = float(line_split[0]) |
||||
|
cor[vI, 1] = float(line_split[1]) |
||||
|
cor[vI, 2] = float(line_split[2]) |
||||
|
|
||||
|
elem = np.empty((nele, 4), dtype=np.int32) |
||||
|
for eleI in range(nele): |
||||
|
line = f.readline() |
||||
|
line_split = line.split() |
||||
|
elem[eleI, 0] = int(line_split[0]) |
||||
|
elem[eleI, 1] = int(line_split[1]) |
||||
|
elem[eleI, 2] = int(line_split[2]) |
||||
|
elem[eleI, 3] = int(line_split[3]) |
||||
|
elem = elem - 1 |
||||
|
return nvet, nele, cor, elem |
||||
|
|
||||
|
|
||||
|
def readT(nvet, filePath): |
||||
|
T = np.empty((nvet), dtype=np.float64) |
||||
|
with open(filePath, 'r') as f: |
||||
|
for vI in range(nvet): |
||||
|
line = f.readline() |
||||
|
line_split = line.split() |
||||
|
T[vI] = float(line_split[0]) |
||||
|
return T |
||||
|
|
||||
|
|
||||
|
# generate element stiffness matrix |
||||
|
# @input |
||||
|
# D: constitutive matrix |
||||
|
# X: 4*3 matrix, which is corridinates of element vertices |
||||
|
# T: vector of 4 size |
||||
|
# @output |
||||
|
# KE: element stiffness matrix |
||||
|
def initKE(D, X, T): |
||||
|
H = np.array([[1., X[0, 0], X[0, 1], X[0, 2]], |
||||
|
[1., X[1, 0], X[1, 1], X[1, 2]], |
||||
|
[1., X[2, 0], X[2, 1], X[2, 2]], |
||||
|
[1., X[3, 0], X[3, 1], X[3, 2]]]) |
||||
|
V6 = abs(np.linalg.det(H)) |
||||
|
|
||||
|
a1 = np.linalg.det(H[[1, 2, 3], :][:, [1, 2, 3]]) |
||||
|
a2 = -np.linalg.det(H[[0, 2, 3], :][:, [1, 2, 3]]) |
||||
|
a3 = np.linalg.det(H[[0, 1, 3], :][:, [1, 2, 3]]) |
||||
|
a4 = -np.linalg.det(H[[0, 1, 2], :][:, [1, 2, 3]]) |
||||
|
|
||||
|
b1 = -np.linalg.det(H[[1, 2, 3], :][:, [0, 2, 3]]) |
||||
|
b2 = np.linalg.det(H[[0, 2, 3], :][:, [0, 2, 3]]) |
||||
|
b3 = -np.linalg.det(H[[0, 1, 3], :][:, [0, 2, 3]]) |
||||
|
b4 = np.linalg.det(H[[0, 1, 2], :][:, [0, 2, 3]]) |
||||
|
|
||||
|
c1 = np.linalg.det(H[[1, 2, 3], :][:, [0, 1, 3]]) |
||||
|
c2 = -np.linalg.det(H[[0, 2, 3], :][:, [0, 1, 3]]) |
||||
|
c3 = np.linalg.det(H[[0, 1, 3], :][:, [0, 1, 3]]) |
||||
|
c4 = -np.linalg.det(H[[0, 1, 2], :][:, [0, 1, 3]]) |
||||
|
|
||||
|
d1 = -np.linalg.det(H[[1, 2, 3], :][:, [0, 1, 2]]) |
||||
|
d2 = np.linalg.det(H[[0, 2, 3], :][:, [0, 1, 2]]) |
||||
|
d3 = -np.linalg.det(H[[0, 1, 3], :][:, [0, 1, 2]]) |
||||
|
d4 = np.linalg.det(H[[0, 1, 2], :][:, [0, 1, 2]]) |
||||
|
|
||||
|
B = np.empty((6, 12), dtype=np.float64) |
||||
|
|
||||
|
B[:, 0:3] = np.array([[b1, 0., 0.], |
||||
|
[0., c1, 0.], |
||||
|
[0., 0., d1], |
||||
|
[c1, b1, 0.], |
||||
|
[0., d1, c1], |
||||
|
[d1, 0., b1]]) |
||||
|
|
||||
|
B[:, 3:6] = np.array([[b2, 0., 0.], |
||||
|
[0., c2, 0.], |
||||
|
[0., 0., d2], |
||||
|
[c2, b2, 0.], |
||||
|
[0., d2, c2], |
||||
|
[d2, 0., b2]]) |
||||
|
|
||||
|
B[:, 6:9] = np.array([[b3, 0., 0.], |
||||
|
[0., c3, 0.], |
||||
|
[0., 0., d3], |
||||
|
[c3, b3, 0.], |
||||
|
[0., d3, c3], |
||||
|
[d3, 0., b3]]) |
||||
|
|
||||
|
B[:, 9:12] = np.array([[b4, 0., 0.], |
||||
|
[0., c4, 0.], |
||||
|
[0., 0., d4], |
||||
|
[c4, b4, 0.], |
||||
|
[0., d4, c4], |
||||
|
[d4, 0., b4]]) |
||||
|
|
||||
|
B = B / V6 |
||||
|
KE = V6 / 6.0 * (B.T @ D @ B) |
||||
|
|
||||
|
strain = np.mean(T) * np.array([1., 1., 1., 0., 0., 0.]) |
||||
|
Fe = V6 / 6.0 * (B.T @ D @ strain) |
||||
|
|
||||
|
return KE, Fe |
||||
|
|
||||
|
|
||||
|
if __name__ == '__main__': |
||||
|
fem3d_tet_linear() |
File diff suppressed because it is too large
File diff suppressed because it is too large
Loading…
Reference in new issue