Skip to content

Commit

Permalink
Merge pull request #1453 from brighthe/develop
Browse files Browse the repository at this point in the history
更新 SOPTX 程序
  • Loading branch information
weihuayi authored Jan 15, 2025
2 parents 401170d + 4b42725 commit ec27d47
Show file tree
Hide file tree
Showing 5 changed files with 232 additions and 44 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
外齿轮 15 个载荷点的算例
外齿轮 1 个载荷点的算例 (左右齿面)
"""
from fealpy.backend import backend_manager as bm
from fealpy.mesh import HexahedronMesh
Expand All @@ -14,21 +14,14 @@
from soptx.utils import timer

from app.soptx.linear_elasticity.JingYiGearProject.utils import export_to_inp
from app.gearx.gear import ExternalGear, InternalGear
from app.gearx.gear import ExternalGear
import json

def compute_strain_stress(tensor_space, uh, B_BBar, D):
cell2tdof = tensor_space.cell_to_dof()
cuh = uh[cell2tdof] # (NC, TLDOF)
strain = bm.einsum('cqil, cl -> cqi', B_BBar, cuh) # (NC, NQ, 6)
stress = bm.einsum('cqij, cqi -> cqj', D, strain) # (NC, NQ, 6)

return strain, stress

bm.set_backend('numpy')

with open('/home/heliang/FEALPy_Development/fealpy/app/soptx/linear_elasticity/JingYiGearProject/json/external_gear_data.json', 'r') \
as file:data = json.load(file)
with open(
'/home/heliang/FEALPy_Development/fealpy/app/soptx/linear_elasticity/JingYiGearProject/json/external_gear_data.json', 'r') \
as file:data = json.load(file)
m_n = data['mn'] # 法向模数
z = data['z'] # 齿数
alpha_n = data['alpha_n'] # 法向压力角
Expand Down Expand Up @@ -99,22 +92,23 @@ def compute_strain_stress(tensor_space, uh, B_BBar, D):
bform.add_integrator(integrator_K)
K = bform.assembly(format='csr')

# 齿面上的节点索引和坐标
node_indices_tuple, noe_coord_tuple = external_gear.get_profile_node_index(tooth_tag=0)
# 齿面上的节点索引, 坐标和内法线方向
node_indices_tuple, node_coord_tuple, profile_node_normal_tuple = external_gear.get_profile_node_index(tooth_tag=0)
node_indices_left = node_indices_tuple[0].reshape(-1, 1)
node_indices_right = node_indices_tuple[1].reshape(-1, 1)
node_indices = bm.concatenate([node_indices_left, node_indices_right], axis=0) # (NPN, 1)
node_coord_left = noe_coord_tuple[0].reshape(-1, 3)
node_coord_right = noe_coord_tuple[1].reshape(-1, 3)
node_coord_left = node_coord_tuple[0].reshape(-1, 3)
node_coord_right = node_coord_tuple[1].reshape(-1, 3)
node_coord = bm.concatenate([node_coord_left, node_coord_right], axis=0) # (NPN, GD)
profile_node_normal_left = profile_node_normal_tuple[0].reshape(-1, 3)
profile_node_normal_right = profile_node_normal_tuple[1].reshape(-1, 3)
profile_node_normal = bm.concatenate([profile_node_normal_left, profile_node_normal_right], axis=0) # (NPN, GD)
# 齿面上的节点数
NPN = node_indices.shape[0]
# TODO 齿面上节点的内法线方向
face_normal = bm.ones((NPN, 3), bm.float64)
# 节点载荷值
load_values = 1000
# 所有节点的内法线载荷向量
P = load_values * face_normal # (NPN, 3)
P = load_values * profile_node_normal # (NPN, GD)
# 齿面上节点对应的全局自由度编号(跟顺序有关)
if tensor_space.dof_priority:
dof_indices = bm.stack([sgdof * d + node_indices.reshape(-1) for d in range(GD)], axis=1) # (NPN, GD)
Expand All @@ -134,7 +128,7 @@ def compute_strain_stress(tensor_space, uh, B_BBar, D):
method='interp')
# 齿面上所有节点的位移结果
uh_profiles = bm.zeros((NPN, GD), dtype=bm.float64) # (NPN, GD)
for i in range(3):
for i in range(NPN):
# 创建计时器
t = timer(f"Timing_{i}")
next(t) # 启动计时器
Expand All @@ -153,10 +147,10 @@ def compute_strain_stress(tensor_space, uh, B_BBar, D):
logger.setLevel('INFO')
uh = tensor_space.function()
# uh[:] = cg(K, F, maxiter=10000, atol=1e-8, rtol=1e-8)
uh[:] = spsolve(K, F, solver="mumps")
uh[:] = spsolve(K, F, solver="mumps") # (tgdof, )
t.send('求解时间')
# 获取齿面上节点的位移
uh_profile = uh[dof_indices[i, :]]
uh_profile = uh[dof_indices[i, :]] # (GD, )
uh_profiles[i, :] = uh_profile
# 计算残差向量和范数
residual = K.matmul(uh[:]) - F
Expand Down Expand Up @@ -185,5 +179,5 @@ def compute_strain_stress(tensor_space, uh, B_BBar, D):
young_modulus=206e3, poisson_ratio=0.3, density=7.85e-9,
used_app='abaqus', mesh_type='hex')
# 计算齿面上节点的内法线方向位移
uh_normal = bm.sum(uh_profiles * face_normal, axis=1) # (NPN, )
uh_normal = bm.sum(uh_profiles * profile_node_normal, axis=1) # (NPN, )
print("-----------")
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
"""
外齿轮 15 个载荷点的算例
内齿轮 15 个载荷点的算例
"""
from fealpy.backend import backend_manager as bm
from fealpy.functionspace import LagrangeFESpace, TensorFunctionSpace
Expand Down
183 changes: 183 additions & 0 deletions app/soptx/linear_elasticity/JingYiGearProject/internal_gear_profile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
"""
内齿轮 1 个载荷点的算例 (左右齿面)
"""
from fealpy.backend import backend_manager as bm
from fealpy.functionspace import LagrangeFESpace, TensorFunctionSpace
from fealpy.sparse import COOTensor
from fealpy.fem.linear_elastic_integrator import LinearElasticIntegrator
from fealpy.material.elastic_material import LinearElasticMaterial
from fealpy.fem.bilinear_form import BilinearForm
from fealpy.fem.dirichlet_bc import DirichletBC
from fealpy.solver import cg, spsolve
from fealpy.mesh import HexahedronMesh

from soptx.utils import timer
from app.soptx.linear_elasticity.JingYiGearProject.utils import export_to_inp
from app.gearx.gear import InternalGear
import json

bm.set_backend('numpy')

with open(
'/home/heliang/FEALPy_Development/fealpy/app/soptx/linear_elasticity/JingYiGearProject/json/internal_gear_data.json', 'r') \
as file:data = json.load(file)
m_n = data['mn'] # 法向模数
z = data['z'] # 齿数
alpha_n = data['alpha_n'] # 法向压力角
beta = data['beta'] # 螺旋角
x_n = data['xn'] # 法向变位系数
hac = data['hac'] # 齿顶高系数
cc = data['cc'] # 顶隙系数
rcc = data['rcc'] # 刀尖圆弧半径
jn = data['jn'] # 法向侧隙
n1 = data['n1'] # 渐开线分段数
n2 = data['n2'] # 过渡曲线分段数
n3 = data['n3']
na = data['na']
nf = data['nf']
nw = data['nw']
tooth_width = data['tooth_width']
outer_diam = data['outer_diam'] # 轮缘内径
z_cutter = data['z_cutter']
xn_cutter = data['xn_cutter']

internal_gear = InternalGear(m_n, z, alpha_n, beta, x_n, hac, cc, rcc, jn, n1, n2, n3, na, nf, nw, outer_diam, z_cutter,
xn_cutter, tooth_width)
hex_mesh = internal_gear.generate_hexahedron_mesh()
target_hex_mesh = internal_gear.set_target_tooth([0, 1, 2, 78, 79])

hex_cell = target_hex_mesh.cell
hex_node = target_hex_mesh.node
# 寻找外圈上节点
node_r = bm.sqrt(hex_node[:, 0] ** 2 + hex_node[:, 1] ** 2)
is_outer_node = bm.abs(node_r - internal_gear.outer_diam / 2) < 1e-11
outer_node_idx = bm.where(bm.abs(node_r - internal_gear.outer_diam / 2)<1e-11)[0]
mesh = HexahedronMesh(hex_node, hex_cell)

GD = mesh.geo_dimension()
NC = mesh.number_of_cells()
print(f"NC: {NC}")
NN = mesh.number_of_nodes()
print(f"NN: {NN}")
node = mesh.entity('node')
cell = mesh.entity('cell')

# 创建有限元空间
p = 1
q = 2
space = LagrangeFESpace(mesh, p=p, ctype='C')
sgdof = space.number_of_global_dofs()
print(f"sgdof: {sgdof}")
cell2dof = space.cell_to_dof()
tensor_space = TensorFunctionSpace(space, shape=(-1, 3)) # gd_priority
cell2tdof = tensor_space.cell_to_dof()
tgdof = tensor_space.number_of_global_dofs()
print(f"tgdof: {tgdof}")
tldof = tensor_space.number_of_local_dofs()

# 组装刚度矩阵
E = 206e3
nu = 0.3
lam = (E * nu) / ((1.0 + nu) * (1.0 - 2.0 * nu))
mu = E / (2.0 * (1.0 + nu))
linear_elastic_material = LinearElasticMaterial(name='E_nu',
elastic_modulus=E, poisson_ratio=nu,
hypo='3D', device=bm.get_device(mesh))
# B-Bar 修正的刚度矩阵
integrator_K = LinearElasticIntegrator(material=linear_elastic_material,
q=q, method='C3D8_BBar')
integrator_K.keep_data(True)
_, _, D, B_BBar = integrator_K.fetch_c3d8_bbar_assembly(tensor_space)
bform = BilinearForm(tensor_space)
bform.add_integrator(integrator_K)
K = bform.assembly(format='csr')

# 齿面上的节点索引, 坐标和内法线方向
node_indices_tuple, node_coord_tuple, profile_node_normal_tuple = internal_gear.get_profile_node_index(tooth_tag=0)
node_indices_left = node_indices_tuple[0].reshape(-1, 1)
node_indices_right = node_indices_tuple[1].reshape(-1, 1)
node_indices = bm.concatenate([node_indices_left, node_indices_right], axis=0) # (NPN, 1)
node_coord_left = node_coord_tuple[0].reshape(-1, 3)
node_coord_right = node_coord_tuple[1].reshape(-1, 3)
node_coord = bm.concatenate([node_coord_left, node_coord_right], axis=0) # (NPN, GD)
profile_node_normal_left = profile_node_normal_tuple[0].reshape(-1, 3)
profile_node_normal_right = profile_node_normal_tuple[1].reshape(-1, 3)
profile_node_normal = bm.concatenate([profile_node_normal_left, profile_node_normal_right], axis=0) # (NPN, GD)
# 齿面上的节点数
NPN = node_indices.shape[0]
# 节点载荷值
load_values = 1000
# 所有节点的内法线载荷向量
P = load_values * profile_node_normal # (NPN, GD)
# 齿面上节点对应的全局自由度编号(跟顺序有关)
if tensor_space.dof_priority:
dof_indices = bm.stack([sgdof * d + node_indices.reshape(-1) for d in range(GD)], axis=1) # (NPN, GD)
else:
dof_indices = bm.stack([node_indices.reshape(-1) * GD + d for d in range(GD)], axis=1) # (NPN, GD)
# inp 文件中需要的固定节点索引
fixed_node_index = bm.where(is_outer_node)[0]
# Dirichlet 边界条件
scalar_is_bd_dof = bm.zeros(sgdof, dtype=bm.bool)
scalar_is_bd_dof[:NN] = is_outer_node
tensor_is_bd_dof = tensor_space.is_boundary_dof(
threshold=(scalar_is_bd_dof, scalar_is_bd_dof, scalar_is_bd_dof),
method='interp')
dbc = DirichletBC(space=tensor_space,
gd=bm.zeros(tgdof),
threshold=tensor_is_bd_dof,
method='interp')
# 齿面上所有节点的位移结果
uh_profiles = bm.zeros((NPN, GD), dtype=bm.float64) # (NPN, GD)
for i in range(NPN):
# 创建计时器
t = timer(f"Timing_{i}")
next(t) # 启动计时器
PP = P[i, :]
# 全局载荷向量
F = COOTensor(indices = bm.empty((1, 0), dtype=bm.int32, device=bm.get_device(space)),
values = bm.empty((0, ), dtype=bm.float64, device=bm.get_device(space)),
spshape = (tgdof, ))
indices = dof_indices[i].reshape(1, -1)
F = F.add(COOTensor(indices, PP.reshape(-1), (tgdof, ))).to_dense() # (tgdof, )
# 处理 Dirichlet 边界条件
K, F = dbc.apply(K, F)
t.send('准备时间')
# 计算位移
from fealpy import logger
logger.setLevel('INFO')
uh = tensor_space.function()
# uh[:] = cg(K, F, maxiter=10000, atol=1e-8, rtol=1e-8)
uh[:] = spsolve(K, F, solver="mumps") # (tgdof, )
t.send('求解时间')
# 获取齿面上节点的位移
uh_profile = uh[dof_indices[i, :]] # (GD, )
uh_profiles[i, :] = uh_profile
# 计算残差向量和范数
residual = K.matmul(uh[:]) - F
residual_norm = bm.sqrt(bm.sum(residual * residual))
print(f"Final residual norm: {residual_norm:.6e}")
t.send('后处理时间')
t.send(None)
if i == 0:
# 保存单个节点的位移结果
if tensor_space.dof_priority:
uh_show = uh.reshape(GD, NN).T
else:
uh_show = uh.reshape(NN, GD)
uh_magnitude = bm.linalg.norm(uh_show, axis=1)
mesh.nodedata['uh'] = uh_show[:]
mesh.nodedata['uh_magnitude'] = uh_magnitude[:]
mesh.to_vtk(f'/home/heliang/FEALPy_Development/fealpy/app/soptx/linear_elasticity/JingYiGearProject/vtu/internal_gear_profile_fealpy_{i}.vtu')

# 单个节点载荷的索引
load_node_indices = node_indices[i].reshape(-1) # (1, )
# 从全局载荷向量中提取单个载荷节点处的值
F_load_nodes = F[dof_indices[i, :].reshape(1, -1)] # (1, GD)
export_to_inp(filename=f'/home/heliang/FEALPy_Development/fealpy/app/soptx/linear_elasticity/JingYiGearProject/inp/internal_gear_profile_abaqus_{i}.inp',
nodes=node, elements=cell,
fixed_nodes=fixed_node_index, load_nodes=load_node_indices, loads=F_load_nodes,
young_modulus=206e3, poisson_ratio=0.3, density=7.85e-9,
used_app='abaqus', mesh_type='hex')
# 计算齿面上节点的内法线方向位移
uh_normal = bm.sum(uh_profiles * profile_node_normal, axis=1) # (NPN, )
print("-----------")
14 changes: 8 additions & 6 deletions app/soptx/soptx/opt/mma.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ def _update_asymptotes(self,
else:
factor = bm.ones((xval.shape[0], 1))
xxx = (xval - xold1) * (xold1 - xold2)
factor[xxx > 0] = asyincr
factor[xxx < 0] = asydecr
factor[xxx == 0] = 1.0
epsilon = 1e-12
factor[xxx > epsilon] = asyincr
factor[xxx < -epsilon] = asydecr

self._low = xval - factor * (xold1 - self._low)
self._upp = xval + factor * (self._upp - xold1)
Expand All @@ -136,7 +136,7 @@ def _update_asymptotes(self,
self._low = bm.minimum(self._low, lowmax)
self._upp = bm.minimum(self._upp, uppmax)
self._upp = bm.maximum(self._upp, uppmin)

return self._low, self._upp

def _solve_subproblem(self,
Expand All @@ -151,6 +151,7 @@ def _solve_subproblem(self,
"""求解 MMA 子问题
Paramters
- xval (n, 1): 当前设计变量
- df0dx (n, 1): 目标函数的梯度
- dfdx (m, n): 约束函数的梯度
Expand Down Expand Up @@ -282,14 +283,15 @@ def optimize(self, rho: TensorLike, **kwargs) -> Tuple[TensorLike, OptimizationH
# MMA 方法
volfrac = self.constraint.volume_fraction
# 体积约束对设计变量的标准化梯度
fval = bm.sum(rho_phys[:]) / (volfrac * obj_grad.shape[0]) - 1
dfdx = con_grad[:, None].T / (volfrac * con_grad.shape[0]) # (m, n)
rho_new, low, upp = self._solve_subproblem(
rho[:, None], fval=con_val,
xval=rho[:, None], fval=fval,
df0dx=obj_grad[:, None], dfdx=dfdx,
low=low, upp=upp,
xold1=xold1[:, None], xold2=xold2[..., None]
)

# 更新物理密度
if self.filter is not None:
rho_phys = self.filter.filter_density(rho_new, filter_params)
Expand Down
37 changes: 23 additions & 14 deletions app/soptx/soptx/tests/test_cantilever_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ class TestConfig:
# 新增优化器类型参数
optimizer_type: Literal['oc', 'mma'] = 'oc' # 默认使用 OC 方法
max_iterations: int = 200
tolerance: float = 0.001
tolerance: float = 0.01

# OC 优化器的参数
move_limit: float = 0.2
Expand Down Expand Up @@ -189,30 +189,39 @@ def run_optimization_test(config: TestConfig) -> Dict[str, Any]:
}

if __name__ == "__main__":
base_dir = '/home/heliang/FEALPy_Development/fealpy/app/soptx/soptx/vtu'

# 使用 OC 优化器的配置
filter_type = 'density'
optimizer_type = 'oc'
config1 = TestConfig(
nx=160, ny=100, nz=4,
volume_fraction=0.4,
filter_radius=6.0,
filter_type='sensitivity',
max_iterations=100,
save_dir='/home/heliang/FEALPy_Development/fealpy/app/soptx/soptx/tests/cantilever_3d_oc',
mesh_type='uniform_mesh_2d',
assembly_method=AssemblyMethod.FAST_STRESS_UNIFORM,
optimizer_type='oc' # 指定使用 OC 优化器
nx=60, ny=20, nz=4,
volume_fraction=0.3,
filter_radius=1.5,
filter_type=filter_type, # 指定使用密度滤波器
save_dir=f'{base_dir}/cantilever_3d_{filter_type}_{optimizer_type}',
mesh_type='uniform_mesh_3d',
assembly_method=AssemblyMethod.FAST_3D_UNIFORM,
optimizer_type=optimizer_type, # 指定使用 OC 优化器
max_iterations=200,
tolerance=0.01

)

# 使用 MMA 优化器的配置
filter_type = 'density'
optimizer_type = 'mma'
config2 = TestConfig(
nx=60, ny=20, nz=4,
volume_fraction=0.3,
filter_radius=1.5,
filter_type='density',
max_iterations=15,
save_dir='/home/heliang/FEALPy_Development/fealpy/app/soptx/soptx/tests/cantilever_3d_mma',
filter_type=filter_type, # 指定使用密度滤波器
save_dir=f'{base_dir}/cantilever_3d_{filter_type}_{optimizer_type}',
mesh_type='uniform_mesh_3d',
assembly_method=AssemblyMethod.FAST_3D_UNIFORM,
optimizer_type='mma' # 指定使用 MMA 优化器
optimizer_type=optimizer_type, # 指定使用 OC 优化器
max_iterations=200,
tolerance=0.01
)

result = run_optimization_test(config2)
Expand Down

0 comments on commit ec27d47

Please sign in to comment.