Update TO_Cal.py

This commit is contained in:
p15806732 2022-11-04 11:24:03 +08:00
parent 976d2cb704
commit fdc33b608c
1 changed files with 12 additions and 151 deletions

View File

@ -1,14 +1,15 @@
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 23 15:08:01 2020
@author: zzy
Object: 存储TO计算过程所需的函数
1. 所有函数均可jit
2. 在调用时 选择在最外层封装jit 内层函数则将jit注释
3. 对于部分确定的static variable 应采用numpy定义(仅限CPU)
"""
'''
@ Copyright (c) 2022 by Zeyu Zhang, All Rights Reserved.
@ Author : Zeyu Zhang
@ Email : zhangzeyu_work@outlook.com
@ Date : 2021-11-17 10:52:26
@ LastEditTime : 2022-10-25 09:33:11
@ FilePath : /ZZY_CODE/Env_JAX/IDRL/Linear_TO/TO_Cal.py
@
@ Description : 存储TO计算过程所需的函数
@ Reference :
'''
import numpy as np
import jax
@ -26,90 +27,28 @@ config.update("jax_enable_x64", True)
@partial(jax.jit, static_argnums=(5, 6, 7))
def design_variable(x, design_area_indices, nondesign_area_indices, filter_kernal, filter_weight, beta_x, volfrac, projection=False):
"""
Parameters
----------
x : shape:[nely, nelx](2D) 经过reshape的NN输出
design_area_indices : 设计域的单元编号索引
nondesign_area_indices : 非设计域的单元编号索引
filter_kernal : TOP88中的H 卷积过滤中的卷积核 计算影响域内每一个单元的权重
filter_weight : TOP88中的HS 设计域内每一个单元的总权重 与网格划分同维度
beta_x : Projection参数
volfrac : 目标体积
projection : 是否采用Projection
Returns
-------
xPhys_1D : shape:[Total_ele](1D) 参与有限元计算的单元相对密度阵
"""
# density filtering 用在了转换之前 目前看也是有效果的
x = filter(x, filter_kernal, filter_weight)
x_1D = x.flatten(order='F')
x_designed = design_and_volume_constraints(
x_1D[design_area_indices], volfrac, beta_x)
xPhys_1D = matrix_set_0(
x_designed, design_area_indices, nondesign_area_indices)
# 直接等于xPhys_1D 但尚需要在真实存在非设计域时验证
# 原始方案
# x_in = x[design_map_bool]
# x_designed = design_and_volume_constraints(x_in, volfrac, beta_x) # x[design_map_bool]内含了一步matrix.flatten()
# x_flat = matrix_set_0(x_designed, jnp.flatnonzero(design_map_bool, size=num_design_ele), Total_ele, num_nondesign_ele)
# 因为x_designed内含flatten() 所以这里对应要复原 由于flatten时没有传入order='F' 这里也不能传入
# xPhys = x_flat.reshape(x.shape)
return xPhys_1D
def projection(x, beta_TONR):
"""
实现projection [-z, z]的数值映射至(0, 1)
目前
原理 tanh能够将元素映射至(-1, 1) 因此 tanh_out * 0.5 + 0.5可以映射至(0, 1)
注意 sigmoid(x) = 0.5 * tanh(0.5 * x) + 0.5
Parameters
----------
x : 待映射的矩阵
beta_TONR : projection函数斜率的控制参数
Returns
-------
output : sigmoid/projection变换后的矩阵
"""
output = jnp.tanh(beta_TONR * 0.5 * x)*.5 + 0.5
return output
def logit(obj_V):
"""
根据obj_V确定sigmoid分母部分e ** (x-b) b搜索的初始上下界
np.clip(a, a_min, a_max) 将a的取值截断在(a_min, a_max)
Parameters
----------
obj_V : 目标体积
Returns
-------
"""
p = jnp.clip(
obj_V, 0, 1)
return jnp.log(p) - jnp.log1p(-p) # p从-inf到inf p取0.5为0 以0.5为界限 大于小于符号相反 数值相同
return jnp.log(p) - jnp.log1p(-p)
# @partial(jax.jit, static_argnums=(1, 2))
def design_and_volume_constraints(x, obj_V, beta_TONR):
"""
用来将神经网络的输出转化为满足设计约束 体积约束和projection的用于有限元计算的单元密度
x_design = 1/(1 + e ** (x - b(x, obj_V)))
Parameters
----------
x : 经过密度过滤后的单元相对密度阵
obj_V : 目标体积.
beta_TONR : Projection参数
Returns
-------
x_design : 满足设计约束和体积约束的相对密度 向量形式
"""
def find_yita(y, x, beta):
projection_out = projection(x + y, beta)
volume_diff = jnp.mean(projection_out) - obj_V
@ -118,28 +57,12 @@ def design_and_volume_constraints(x, obj_V, beta_TONR):
upper_bound = logit(obj_V) - jl.stop_gradient(np.min(x))
bisec = Bisection(optimality_fun=find_yita, lower=lower_bound, upper=upper_bound, tol=1e-12, maxiter=64, check_bracket=False)
yita = bisec.run(x=x, beta=beta_TONR).params
# yita = TPA.binary_search(find_yita, x, beta_TONR, lower_bound, upper_bound) # 自编二分法
# 用来搜索yita的取值 由二分法获得 本质上这里和保体积projection搜索yita的过程完全相同
# 实验和公式表明 在保体积projection和此处添加体积约束的sigmoid中 对yita的求解均是一个关于(x, obj_V)的函数
# 其敏度必然要考虑
x_design = projection(x + yita, beta_TONR)
x_design = x_design + 0.00001
return x_design
def filter_define(design_map, filter_width):
"""
定义TO中过滤器的卷积核 权重等参数
Parameters
----------
design_map : 设计域和非设计域定义矩阵
filter_width : 过滤半径
Returns
-------
filter_kernal : TOP88中的H 卷积过滤中的卷积核 计算影响域内每一个单元的权重
filter_weight : TOP88中的HS 设计域内每一个单元的总权重 与网格划分同维度
"""
dy, dx = jnp.meshgrid(jnp.arange(-jnp.ceil(filter_width)+1, jnp.ceil(filter_width)),
jnp.arange(-jnp.ceil(filter_width)+1, jnp.ceil(filter_width)))
filter_kernal = jnp.maximum(0, filter_width - jnp.sqrt(dx ** 2 + dy ** 2))
@ -149,17 +72,6 @@ def filter_define(design_map, filter_width):
# @jax.jit
def filter(matrixA, filter_kernal, filter_weight):
"""
Parameters
----------
matrixA : 待过滤的矩阵
filter_kernal : TOP88中的H 卷积过滤中的卷积核 计算影响域内每一个单元的权重
filter_weight : TOP88中的HS 设计域内每一个单元的总权重 与网格划分同维度
Returns
-------
new_matrix : 过滤后的矩阵
"""
new_matrix = jss.convolve2d(matrixA, filter_kernal, 'same') / filter_weight
return new_matrix
@ -173,24 +85,6 @@ def inverse_permutation(indices):
# @jax.jit
def matrix_set_0(nonzero_values, nonzero_indices, zero_indices):
"""
补齐矩阵 对原始矩阵指定区域置0 可用于非设计域进行置0 以及节点位移添加指定节点的位移
Parameters
----------
nonzero_values : 已存在数值的矩阵 如设计域的相对密度阵 freedofs对应的节点位移
nonzero_indices : size=存在数值的个数 已存在数值矩阵对应的索引编号 如设计域对应的索引
注意 这里为根据design_map自动生成的 是基于行展开编号的 仅用于此处计算 并非真正TO中的单元编号
zero_indices : 矩阵中未存在数值的单元对应的索引编号
origin_matrix_size : 原始矩阵元素个数 即包含设计域和非设计域
zero_size : 矩阵中0元素的个数 代表非设计域的单元个数
Returns
-------
new_matrix : 补齐后的矩阵
"""
# all_indices = np.arange(origin_matrix_size, dtype=jnp.int64)
# zero_indices = jnp.setdiff1d(
# all_indices, nonzero_indices, size=zero_size, assume_unique=True) # setdiff1d通常不支持jit 需要指定size
index_map = inverse_permutation(
jnp.concatenate([nonzero_indices, zero_indices]))
u_values = jnp.concatenate([nonzero_values, jnp.zeros(len(zero_indices))])
@ -200,19 +94,6 @@ def matrix_set_0(nonzero_values, nonzero_indices, zero_indices):
@partial(jax.jit, static_argnums=(2, 3))
def matrix_set_1(nonzero_values, nonzero_indices, origin_matrix_size, zero_size):
"""
补齐矩阵 对原始矩阵指定区域置1
Parameters
----------
nonzero_values : 已存在数值的矩阵
nonzero_indices : 已存在数值矩阵对应的索引编号
origin_matrix_size : 原始矩阵元素个数 即包含设计域和非设计域
zero_size : 矩阵中0元素的个数 代表非设计域的单元个数
Returns
-------
new_matrix : 补齐后的矩阵
"""
all_indices = jnp.arange(origin_matrix_size, dtype=jnp.int64)
zero_indices = jnp.setdiff1d(
all_indices, nonzero_indices, size=zero_size, assume_unique=True)
@ -225,29 +106,9 @@ def matrix_set_1(nonzero_values, nonzero_indices, origin_matrix_size, zero_size)
@partial(jax.jit, static_argnums=(1, 2, 10))
def objective(xPhys_1D, young, young_min, freedofs, fext, s_K_predefined, dispTD_predefined, idx, edofMat, ke, penal):
"""
Parameters
----------
xPhys_1D : shape:[Total_ele](1D) 参与有限元计算的相对密度
young : 杨氏模量
young_min : 弱单元的杨氏模量
freedofs : 有限元的自由节点
fext : Python中的1D矢量 外力
s_K_predefined : 预定义的刚度阵
dispTD_predefined : 预定义的位移阵
idx : 刚度阵组装编号
edofMat : shape:[Total_ele, 8](2D) 按照单元顺序存储每一个单元的自由度编号
ke : 单元刚度阵 不考虑杨氏模量
penal : 惩罚因子
Returns
-------
obj : 目标函数输出 此处为结构的柔度
"""
# xPhys_1D = xPhys.T.flatten()
disp = TO_FEA.FEA(young, young_min, ke, xPhys_1D, freedofs,
penal, idx, fext, s_K_predefined, dispTD_predefined)
obj = TO_Obj.compliance(young, young_min, ke,
xPhys_1D, edofMat, penal, disp)
# print('obj is running')
return obj