morphopt 3.1.1__tar.gz → 3.1.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {morphopt-3.1.1 → morphopt-3.1.2}/PKG-INFO +33 -9
- {morphopt-3.1.1 → morphopt-3.1.2}/README.md +23 -1
- {morphopt-3.1.1 → morphopt-3.1.2}/pyproject.toml +25 -23
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/__init__.py +3 -2
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/controller.py +50 -15
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/__init__.py +1 -1
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/base_params.py +23 -1
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feaparams.py +3 -1
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/basesurfaceinterface.py +169 -36
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/bspsurfaceinterface.py +229 -65
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/cpgeosurfaceinterface.py +200 -51
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/geometryparams.py +57 -22
- morphopt-3.1.2/src/morphopt/optcore/modelparams/materials/__init__.py +3 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/materials/materialparams.py +0 -11
- morphopt-3.1.2/src/morphopt/optcore/modelparams/materials/simpmaterial.py +430 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/params.py +52 -1
- morphopt-3.1.2/src/morphopt/optcore/objfunc.py +273 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/solver.py +10 -7
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/__init__.py +1 -0
- morphopt-3.1.2/src/morphopt/optcore/updaters/geometry/objectivefuncs/__init__.py +5 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/objectivefuncs/basefuncs.py +4 -5
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/objectivefuncs/distancesurface.py +1 -1
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/objectivefuncs/shapederivative.py +55 -36
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/objectivefuncs/surfacefairness.py +4 -4
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/update_geometry.py +9 -9
- morphopt-3.1.2/src/morphopt/optcore/updaters/materials/__init__.py +1 -0
- morphopt-3.1.2/src/morphopt/optcore/updaters/materials/objectivefuncs/__init__.py +12 -0
- morphopt-3.1.2/src/morphopt/optcore/updaters/materials/objectivefuncs/basefuncs.py +112 -0
- morphopt-3.1.2/src/morphopt/optcore/updaters/materials/objectivefuncs/boundarys.py +71 -0
- morphopt-3.1.2/src/morphopt/optcore/updaters/materials/objectivefuncs/densityfield.py +25 -0
- morphopt-3.1.2/src/morphopt/optcore/updaters/materials/objectivefuncs/sensitivity.py +32 -0
- morphopt-3.1.2/src/morphopt/optcore/updaters/materials/update_material.py +338 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/updaters.py +37 -4
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/taskui.py +11 -9
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt.egg-info/PKG-INFO +33 -9
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt.egg-info/SOURCES.txt +8 -1
- morphopt-3.1.2/src/morphopt.egg-info/requires.txt +17 -0
- morphopt-3.1.1/src/morphopt/optcore/modelparams/materials/__init__.py +0 -1
- morphopt-3.1.1/src/morphopt/optcore/objfunc.py +0 -248
- morphopt-3.1.1/src/morphopt/optcore/updaters/geometry/objectivefuncs/__init__.py +0 -5
- morphopt-3.1.1/src/morphopt/optcore/utils/plot_history_surface.py +0 -239
- morphopt-3.1.1/src/morphopt.egg-info/requires.txt +0 -15
- {morphopt-3.1.1 → morphopt-3.1.2}/setup.cfg +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/opt_runner.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/baseobject.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/history.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/__init__.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/__init__.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/basefeainterface.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/bodyforceinterface.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/boundaryconditioninterface.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/contactinterface.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/coupleinterface.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/pointinterface.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/pressureinterface.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/referencepointinterface.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/springinterface.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/__init__.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/__init__.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/base_updater.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/__init__.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/objectivefuncs/boundarys.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/optimizer.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/taskoptmization.py +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt.egg-info/dependency_links.txt +0 -0
- {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: morphopt
|
|
3
|
-
Version: 3.1.
|
|
3
|
+
Version: 3.1.2
|
|
4
4
|
Summary: A morphing optimization framework using PyTorch and Abaqus.
|
|
5
5
|
Requires-Python: >=3.12
|
|
6
6
|
Description-Content-Type: text/markdown
|
|
@@ -8,23 +8,26 @@ Requires-Dist: torch>=2.0.0
|
|
|
8
8
|
Requires-Dist: torchvision>=0.15.1
|
|
9
9
|
Requires-Dist: numpy>=2.0.0
|
|
10
10
|
Requires-Dist: pypardiso>=0.4.7
|
|
11
|
-
Requires-Dist: pyqt6>=6.
|
|
12
|
-
Requires-Dist: pyvista>=0.
|
|
11
|
+
Requires-Dist: pyqt6>=6.11.0
|
|
12
|
+
Requires-Dist: pyvista>=0.47.1
|
|
13
13
|
Requires-Dist: pyvistaqt>=0.11.3
|
|
14
|
-
Requires-Dist: vtk>=9.
|
|
14
|
+
Requires-Dist: vtk>=9.6.1
|
|
15
15
|
Requires-Dist: gmsh>=4.15.0
|
|
16
16
|
Requires-Dist: tabulate>=0.9.0
|
|
17
|
-
Requires-Dist:
|
|
18
|
-
Requires-Dist: imageio>=2.37.2
|
|
17
|
+
Requires-Dist: imageio>=2.37.3
|
|
19
18
|
Requires-Dist: bspmap>=1.0.0
|
|
20
|
-
Requires-Dist: torchfea>=1.0.
|
|
21
|
-
Requires-Dist: trimesh>=4.11.
|
|
19
|
+
Requires-Dist: torchfea>=1.0.8
|
|
20
|
+
Requires-Dist: trimesh>=4.11.5
|
|
21
|
+
Requires-Dist: networkx>=3.6.1
|
|
22
|
+
Requires-Dist: scipy>=1.17.1
|
|
23
|
+
Requires-Dist: cpgeo>=1.0.5
|
|
22
24
|
|
|
23
25
|
# 项目说明与使用指南
|
|
24
26
|
|
|
25
27
|
本仓库提供基于形状优化的工作流,集成了表面参数化、有限元(FEA)求解、载荷管理与目标函数组合。你可以复用示例快速搭建新任务,或扩展接口以支持更多场景。
|
|
26
28
|
|
|
27
29
|
目录:
|
|
30
|
+
|
|
28
31
|
- 安装与环境
|
|
29
32
|
- 项目结构
|
|
30
33
|
- 快速开始(运行示例)
|
|
@@ -40,10 +43,12 @@ Requires-Dist: trimesh>=4.11.1
|
|
|
40
43
|
## 安装与环境
|
|
41
44
|
|
|
42
45
|
前置条件:
|
|
46
|
+
|
|
43
47
|
- Python 3.10+(建议使用 conda 环境)
|
|
44
48
|
- Windows(已在 Windows+PowerShell 下验证),Linux 也可按需适配
|
|
45
49
|
|
|
46
50
|
安装依赖:
|
|
51
|
+
|
|
47
52
|
```powershell
|
|
48
53
|
# 可选:创建虚拟环境
|
|
49
54
|
conda create -n MorphOpt python=3.10 -y; conda activate MorphOpt
|
|
@@ -57,6 +62,7 @@ pip install -r requirements.txt
|
|
|
57
62
|
## 项目结构
|
|
58
63
|
|
|
59
64
|
参考主要目录:
|
|
65
|
+
|
|
60
66
|
- `Jobs/`:示例与具体任务脚本(建议以 `Jobs/examples/displacement.py` 为模板)。
|
|
61
67
|
- `MorphOpt/`:核心库,包括参数、接口、求解器、更新器等。
|
|
62
68
|
- `Tests/`:简单的可视化/单元测试脚本。
|
|
@@ -66,6 +72,7 @@ pip install -r requirements.txt
|
|
|
66
72
|
## 快速开始(运行示例)
|
|
67
73
|
|
|
68
74
|
运行位移示例(displacement):
|
|
75
|
+
|
|
69
76
|
```powershell
|
|
70
77
|
python Jobs/examples/displacement.py
|
|
71
78
|
```
|
|
@@ -81,15 +88,21 @@ python Jobs/examples/displacement.py
|
|
|
81
88
|
每个任务脚本遵循统一结构:
|
|
82
89
|
|
|
83
90
|
1) 定义目标函数 ObjectiveFunction
|
|
84
|
-
|
|
91
|
+
|
|
92
|
+
- 继承自 `morphopt.ObjectiveFunction`,在 `__init__` 方法中局部定义针对各个加载步(工况)的 `objective` 函数,并将它们按评估顺序组成列表赋给 `self.objective_functions`。
|
|
93
|
+
- 函数签名为 `def objective*(GC: torch.Tensor, jacobian: dict[torch.Tensor], assembly: torchfea.Assembly) -> torch.Tensor`。
|
|
94
|
+
- **重要**:如果目标函数依赖于特定载荷的雅可比矩阵,必须在 `__init__` 中通过提前定义 `self.jacobian_needed = ['载荷接口名称']` 来显式声明需要的项。
|
|
95
|
+
- 同时可以实现 `get_metrics(self)` 返回需要额外追踪的指标或损失(可通过 `self.fe_results[工况索引].GC` 获取内部状态)。
|
|
85
96
|
|
|
86
97
|
2) 定义参数容器 Params(_Params)
|
|
98
|
+
|
|
87
99
|
- 内含三个子类:
|
|
88
100
|
- `SurfaceParams(_SurfacesParams)`:构建可优化的几何曲面(使用 `self.BSP.*` 初始化几何)。
|
|
89
101
|
- `LoadParams(_LoadsParams)`:定义“所有需要的载荷接口”和“每个加载步的幅值参数”。
|
|
90
102
|
- `MaterialParams(_Materials)`:设置材料参数(如 `mu`, `kappa`, `density`)。
|
|
91
103
|
|
|
92
104
|
3) 定义 Generator、Solver、Updater 与 Controller
|
|
105
|
+
|
|
93
106
|
- `Generator(_Generator)`:生成网格/中间数据(可设置 `seed_size`, `mesh_order` 等)。
|
|
94
107
|
- `Solver(_MorphSolver)`:负责调用 FEA;内部会一次性将所有载荷添加到 FEA 中,并在每个加载步切换载荷“幅值”,无需重复初始化模型。
|
|
95
108
|
- `Updater(_Updaters)`:包含 `UpdaterSurfaces(_UpdaterSurfaces)`,在其中添加/组合优化目标项(如形状导数、平滑、边界约束等)。
|
|
@@ -100,10 +113,12 @@ python Jobs/examples/displacement.py
|
|
|
100
113
|
### 曲面定义 SurfaceParams
|
|
101
114
|
|
|
102
115
|
在 `SurfaceParams` 中:
|
|
116
|
+
|
|
103
117
|
- 使用 `self.BSP.*` 工具函数构建一个或多个初始曲面,并通过 `self.add_surface(...)` 注册。
|
|
104
118
|
- 通过 `self.if_update = [...]` 指定哪些曲面参与更新。
|
|
105
119
|
|
|
106
120
|
示例(略化):
|
|
121
|
+
|
|
107
122
|
```python
|
|
108
123
|
class SurfaceParams(_SurfacesParams):
|
|
109
124
|
def __init__(self):
|
|
@@ -120,10 +135,12 @@ class SurfaceParams(_SurfacesParams):
|
|
|
120
135
|
### 载荷定义 LoadParams(关键:一次定义,分步调幅)
|
|
121
136
|
|
|
122
137
|
新的载荷定义方式遵循两个阶段:
|
|
138
|
+
|
|
123
139
|
- 阶段 A:注册“载荷接口”(仅定义类型/关联对象,不写死幅值)。
|
|
124
140
|
- 阶段 B:设置“步数”和“每个步的幅值”。求解时,FEA 只创建一次载荷对象,各步仅切换幅值,避免频繁重建/初始化。
|
|
125
141
|
|
|
126
142
|
LoadParams 提供以下方法:
|
|
143
|
+
|
|
127
144
|
- `add_load_interface(load_interface, name: str | None) -> str`
|
|
128
145
|
- 注册一个载荷接口,返回其唯一名称(若未提供 name 会自动生成)。
|
|
129
146
|
- `set_step_num(num_steps: int)`
|
|
@@ -132,6 +149,7 @@ LoadParams 提供以下方法:
|
|
|
132
149
|
- 为某个加载步的某个载荷设置幅值(如压力标量,力/力矩三分量等)。
|
|
133
150
|
|
|
134
151
|
常用载荷接口(均在 `MorphOpt/modelparams/loads/LoadInterface/` 下):
|
|
152
|
+
|
|
135
153
|
- `PressureInterface(instance_name='final_model', surface_name='...')`
|
|
136
154
|
- 幅值参数:`[pressure]`(单个浮点数)。
|
|
137
155
|
- `ConcentratedForceInterface(rp_name: str)`
|
|
@@ -145,6 +163,7 @@ LoadParams 提供以下方法:
|
|
|
145
163
|
- 自接触约束,同样通常无幅值参数。
|
|
146
164
|
|
|
147
165
|
示例(等价于 `Jobs/examples/displacement.py` 的写法):
|
|
166
|
+
|
|
148
167
|
```python
|
|
149
168
|
class LoadParams(_LoadsParams):
|
|
150
169
|
def __init__(self):
|
|
@@ -161,12 +180,14 @@ class LoadParams(_LoadsParams):
|
|
|
161
180
|
```
|
|
162
181
|
|
|
163
182
|
Solver 会在 solve 时:
|
|
183
|
+
|
|
164
184
|
- 一次性用 `get_loads_fea()` 将全部载荷添加到 FEA。
|
|
165
185
|
- 每个步调用 `process_fea(fea, step_index)` 应用当前步的幅值;模型不需要每步重建、仅切换数值,效率更高。
|
|
166
186
|
|
|
167
187
|
### 材料参数 MaterialParams
|
|
168
188
|
|
|
169
189
|
示例:
|
|
190
|
+
|
|
170
191
|
```python
|
|
171
192
|
class MaterialParams(_Materials):
|
|
172
193
|
def __init__(self):
|
|
@@ -181,11 +202,13 @@ class MaterialParams(_Materials):
|
|
|
181
202
|
## 目标与更新器(Objective/Updater)
|
|
182
203
|
|
|
183
204
|
在 `Updater(_Updaters).UpdaterSurfaces(_UpdaterSurfaces)` 中:
|
|
205
|
+
|
|
184
206
|
- 创建形状导数(如 `ShapeDerivativeDirect(reset_per_iter=5)`)并注册:
|
|
185
207
|
- `self.add_objective_function(shape_derivative)`
|
|
186
208
|
- 可叠加其它目标/正则(如 `Fairness`, `Distance`, `boundarys.Cylinder` 等)。
|
|
187
209
|
|
|
188
210
|
常见用法:
|
|
211
|
+
|
|
189
212
|
- 目标函数统一通过 `self.add_objective_function(...)` 注册。
|
|
190
213
|
- 多目标时,可通过权重在对应目标构造参数中体现。
|
|
191
214
|
|
|
@@ -237,6 +260,7 @@ class MaterialParams(_Materials):
|
|
|
237
260
|
---
|
|
238
261
|
|
|
239
262
|
更多参考:
|
|
263
|
+
|
|
240
264
|
- 示例:`Jobs/examples/displacement.py`
|
|
241
265
|
- 接触/集中载荷用法:`Jobs/locomotion/front.py`、`Jobs/ral2025contact/*`
|
|
242
266
|
- 载荷接口实现:`MorphOpt/modelparams/loads/LoadInterface/`
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
本仓库提供基于形状优化的工作流,集成了表面参数化、有限元(FEA)求解、载荷管理与目标函数组合。你可以复用示例快速搭建新任务,或扩展接口以支持更多场景。
|
|
4
4
|
|
|
5
5
|
目录:
|
|
6
|
+
|
|
6
7
|
- 安装与环境
|
|
7
8
|
- 项目结构
|
|
8
9
|
- 快速开始(运行示例)
|
|
@@ -18,10 +19,12 @@
|
|
|
18
19
|
## 安装与环境
|
|
19
20
|
|
|
20
21
|
前置条件:
|
|
22
|
+
|
|
21
23
|
- Python 3.10+(建议使用 conda 环境)
|
|
22
24
|
- Windows(已在 Windows+PowerShell 下验证),Linux 也可按需适配
|
|
23
25
|
|
|
24
26
|
安装依赖:
|
|
27
|
+
|
|
25
28
|
```powershell
|
|
26
29
|
# 可选:创建虚拟环境
|
|
27
30
|
conda create -n MorphOpt python=3.10 -y; conda activate MorphOpt
|
|
@@ -35,6 +38,7 @@ pip install -r requirements.txt
|
|
|
35
38
|
## 项目结构
|
|
36
39
|
|
|
37
40
|
参考主要目录:
|
|
41
|
+
|
|
38
42
|
- `Jobs/`:示例与具体任务脚本(建议以 `Jobs/examples/displacement.py` 为模板)。
|
|
39
43
|
- `MorphOpt/`:核心库,包括参数、接口、求解器、更新器等。
|
|
40
44
|
- `Tests/`:简单的可视化/单元测试脚本。
|
|
@@ -44,6 +48,7 @@ pip install -r requirements.txt
|
|
|
44
48
|
## 快速开始(运行示例)
|
|
45
49
|
|
|
46
50
|
运行位移示例(displacement):
|
|
51
|
+
|
|
47
52
|
```powershell
|
|
48
53
|
python Jobs/examples/displacement.py
|
|
49
54
|
```
|
|
@@ -59,15 +64,21 @@ python Jobs/examples/displacement.py
|
|
|
59
64
|
每个任务脚本遵循统一结构:
|
|
60
65
|
|
|
61
66
|
1) 定义目标函数 ObjectiveFunction
|
|
62
|
-
|
|
67
|
+
|
|
68
|
+
- 继承自 `morphopt.ObjectiveFunction`,在 `__init__` 方法中局部定义针对各个加载步(工况)的 `objective` 函数,并将它们按评估顺序组成列表赋给 `self.objective_functions`。
|
|
69
|
+
- 函数签名为 `def objective*(GC: torch.Tensor, jacobian: dict[torch.Tensor], assembly: torchfea.Assembly) -> torch.Tensor`。
|
|
70
|
+
- **重要**:如果目标函数依赖于特定载荷的雅可比矩阵,必须在 `__init__` 中通过提前定义 `self.jacobian_needed = ['载荷接口名称']` 来显式声明需要的项。
|
|
71
|
+
- 同时可以实现 `get_metrics(self)` 返回需要额外追踪的指标或损失(可通过 `self.fe_results[工况索引].GC` 获取内部状态)。
|
|
63
72
|
|
|
64
73
|
2) 定义参数容器 Params(_Params)
|
|
74
|
+
|
|
65
75
|
- 内含三个子类:
|
|
66
76
|
- `SurfaceParams(_SurfacesParams)`:构建可优化的几何曲面(使用 `self.BSP.*` 初始化几何)。
|
|
67
77
|
- `LoadParams(_LoadsParams)`:定义“所有需要的载荷接口”和“每个加载步的幅值参数”。
|
|
68
78
|
- `MaterialParams(_Materials)`:设置材料参数(如 `mu`, `kappa`, `density`)。
|
|
69
79
|
|
|
70
80
|
3) 定义 Generator、Solver、Updater 与 Controller
|
|
81
|
+
|
|
71
82
|
- `Generator(_Generator)`:生成网格/中间数据(可设置 `seed_size`, `mesh_order` 等)。
|
|
72
83
|
- `Solver(_MorphSolver)`:负责调用 FEA;内部会一次性将所有载荷添加到 FEA 中,并在每个加载步切换载荷“幅值”,无需重复初始化模型。
|
|
73
84
|
- `Updater(_Updaters)`:包含 `UpdaterSurfaces(_UpdaterSurfaces)`,在其中添加/组合优化目标项(如形状导数、平滑、边界约束等)。
|
|
@@ -78,10 +89,12 @@ python Jobs/examples/displacement.py
|
|
|
78
89
|
### 曲面定义 SurfaceParams
|
|
79
90
|
|
|
80
91
|
在 `SurfaceParams` 中:
|
|
92
|
+
|
|
81
93
|
- 使用 `self.BSP.*` 工具函数构建一个或多个初始曲面,并通过 `self.add_surface(...)` 注册。
|
|
82
94
|
- 通过 `self.if_update = [...]` 指定哪些曲面参与更新。
|
|
83
95
|
|
|
84
96
|
示例(略化):
|
|
97
|
+
|
|
85
98
|
```python
|
|
86
99
|
class SurfaceParams(_SurfacesParams):
|
|
87
100
|
def __init__(self):
|
|
@@ -98,10 +111,12 @@ class SurfaceParams(_SurfacesParams):
|
|
|
98
111
|
### 载荷定义 LoadParams(关键:一次定义,分步调幅)
|
|
99
112
|
|
|
100
113
|
新的载荷定义方式遵循两个阶段:
|
|
114
|
+
|
|
101
115
|
- 阶段 A:注册“载荷接口”(仅定义类型/关联对象,不写死幅值)。
|
|
102
116
|
- 阶段 B:设置“步数”和“每个步的幅值”。求解时,FEA 只创建一次载荷对象,各步仅切换幅值,避免频繁重建/初始化。
|
|
103
117
|
|
|
104
118
|
LoadParams 提供以下方法:
|
|
119
|
+
|
|
105
120
|
- `add_load_interface(load_interface, name: str | None) -> str`
|
|
106
121
|
- 注册一个载荷接口,返回其唯一名称(若未提供 name 会自动生成)。
|
|
107
122
|
- `set_step_num(num_steps: int)`
|
|
@@ -110,6 +125,7 @@ LoadParams 提供以下方法:
|
|
|
110
125
|
- 为某个加载步的某个载荷设置幅值(如压力标量,力/力矩三分量等)。
|
|
111
126
|
|
|
112
127
|
常用载荷接口(均在 `MorphOpt/modelparams/loads/LoadInterface/` 下):
|
|
128
|
+
|
|
113
129
|
- `PressureInterface(instance_name='final_model', surface_name='...')`
|
|
114
130
|
- 幅值参数:`[pressure]`(单个浮点数)。
|
|
115
131
|
- `ConcentratedForceInterface(rp_name: str)`
|
|
@@ -123,6 +139,7 @@ LoadParams 提供以下方法:
|
|
|
123
139
|
- 自接触约束,同样通常无幅值参数。
|
|
124
140
|
|
|
125
141
|
示例(等价于 `Jobs/examples/displacement.py` 的写法):
|
|
142
|
+
|
|
126
143
|
```python
|
|
127
144
|
class LoadParams(_LoadsParams):
|
|
128
145
|
def __init__(self):
|
|
@@ -139,12 +156,14 @@ class LoadParams(_LoadsParams):
|
|
|
139
156
|
```
|
|
140
157
|
|
|
141
158
|
Solver 会在 solve 时:
|
|
159
|
+
|
|
142
160
|
- 一次性用 `get_loads_fea()` 将全部载荷添加到 FEA。
|
|
143
161
|
- 每个步调用 `process_fea(fea, step_index)` 应用当前步的幅值;模型不需要每步重建、仅切换数值,效率更高。
|
|
144
162
|
|
|
145
163
|
### 材料参数 MaterialParams
|
|
146
164
|
|
|
147
165
|
示例:
|
|
166
|
+
|
|
148
167
|
```python
|
|
149
168
|
class MaterialParams(_Materials):
|
|
150
169
|
def __init__(self):
|
|
@@ -159,11 +178,13 @@ class MaterialParams(_Materials):
|
|
|
159
178
|
## 目标与更新器(Objective/Updater)
|
|
160
179
|
|
|
161
180
|
在 `Updater(_Updaters).UpdaterSurfaces(_UpdaterSurfaces)` 中:
|
|
181
|
+
|
|
162
182
|
- 创建形状导数(如 `ShapeDerivativeDirect(reset_per_iter=5)`)并注册:
|
|
163
183
|
- `self.add_objective_function(shape_derivative)`
|
|
164
184
|
- 可叠加其它目标/正则(如 `Fairness`, `Distance`, `boundarys.Cylinder` 等)。
|
|
165
185
|
|
|
166
186
|
常见用法:
|
|
187
|
+
|
|
167
188
|
- 目标函数统一通过 `self.add_objective_function(...)` 注册。
|
|
168
189
|
- 多目标时,可通过权重在对应目标构造参数中体现。
|
|
169
190
|
|
|
@@ -215,6 +236,7 @@ class MaterialParams(_Materials):
|
|
|
215
236
|
---
|
|
216
237
|
|
|
217
238
|
更多参考:
|
|
239
|
+
|
|
218
240
|
- 示例:`Jobs/examples/displacement.py`
|
|
219
241
|
- 接触/集中载荷用法:`Jobs/locomotion/front.py`、`Jobs/ral2025contact/*`
|
|
220
242
|
- 载荷接口实现:`MorphOpt/modelparams/loads/LoadInterface/`
|
|
@@ -1,23 +1,25 @@
|
|
|
1
|
-
[project]
|
|
2
|
-
name = "morphopt"
|
|
3
|
-
version = "3.1.
|
|
4
|
-
description = "A morphing optimization framework using PyTorch and Abaqus."
|
|
5
|
-
readme = "README.md"
|
|
6
|
-
requires-python = ">=3.12"
|
|
7
|
-
dependencies = [
|
|
8
|
-
"torch>=2.0.0",
|
|
9
|
-
"torchvision>=0.15.1",
|
|
10
|
-
"numpy>=2.0.0",
|
|
11
|
-
"pypardiso>=0.4.7",
|
|
12
|
-
"pyqt6>=6.
|
|
13
|
-
"pyvista>=0.
|
|
14
|
-
"pyvistaqt>=0.11.3",
|
|
15
|
-
"vtk>=9.
|
|
16
|
-
"gmsh>=4.15.0",
|
|
17
|
-
"tabulate>=0.9.0",
|
|
18
|
-
"
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
|
|
1
|
+
[project]
|
|
2
|
+
name = "morphopt"
|
|
3
|
+
version = "3.1.2"
|
|
4
|
+
description = "A morphing optimization framework using PyTorch and Abaqus."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.12"
|
|
7
|
+
dependencies = [
|
|
8
|
+
"torch>=2.0.0",
|
|
9
|
+
"torchvision>=0.15.1",
|
|
10
|
+
"numpy>=2.0.0",
|
|
11
|
+
"pypardiso>=0.4.7",
|
|
12
|
+
"pyqt6>=6.11.0",
|
|
13
|
+
"pyvista>=0.47.1",
|
|
14
|
+
"pyvistaqt>=0.11.3",
|
|
15
|
+
"vtk>=9.6.1",
|
|
16
|
+
"gmsh>=4.15.0",
|
|
17
|
+
"tabulate>=0.9.0",
|
|
18
|
+
"imageio>=2.37.3",
|
|
19
|
+
"bspmap>=1.0.0",
|
|
20
|
+
"torchfea>=1.0.8",
|
|
21
|
+
"trimesh>=4.11.5",
|
|
22
|
+
"networkx>=3.6.1",
|
|
23
|
+
"scipy>=1.17.1",
|
|
24
|
+
"cpgeo>=1.0.5",
|
|
25
|
+
]
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
# region optcore imports
|
|
2
2
|
from .optcore.controller import Controller
|
|
3
|
-
from .optcore.modelparams import GeometryParams, FEAParams, Materials
|
|
3
|
+
from .optcore.modelparams import GeometryParams, FEAParams, Materials, SIMPMaterials
|
|
4
4
|
from .optcore.solver import MorphSolver
|
|
5
5
|
from .optcore.updaters.geometry import UpdaterGeometries
|
|
6
|
+
from .optcore.updaters.materials import UpdaterMaterials
|
|
6
7
|
from .optcore.updaters.updaters import Updaters
|
|
7
8
|
from .optcore.modelparams import Params
|
|
8
9
|
from .optcore.objfunc import ObjectiveFunction
|
|
9
10
|
from .optcore.history import History
|
|
10
11
|
from .optcore.baseobject import BaseObject
|
|
11
|
-
from .optcore.utils.plot_history_surface import SurfacesFigurePlotter
|
|
12
12
|
# endregion
|
|
13
13
|
|
|
14
14
|
from .opt_runner import start_optimization, debug_optimization, view_optimization_result
|
|
@@ -25,6 +25,7 @@ __all__ = [
|
|
|
25
25
|
"Materials",
|
|
26
26
|
"MorphSolver",
|
|
27
27
|
"UpdaterGeometries",
|
|
28
|
+
"UpdaterMaterials",
|
|
28
29
|
"Updaters",
|
|
29
30
|
"Params",
|
|
30
31
|
"ObjectiveFunction",
|
|
@@ -194,8 +194,7 @@ class Controller:
|
|
|
194
194
|
self.initialize_path(main_filepath=main_filepath)
|
|
195
195
|
self.opt_loop()
|
|
196
196
|
|
|
197
|
-
def
|
|
198
|
-
|
|
197
|
+
def _load_history(self, path_result: str, target_iteration: int = None) -> None:
|
|
199
198
|
self.path_result = path_result
|
|
200
199
|
self.initialize()
|
|
201
200
|
self.history.load(foldpath=self.path_result + '/log/', iteration=target_iteration)
|
|
@@ -209,6 +208,9 @@ class Controller:
|
|
|
209
208
|
|
|
210
209
|
self.history.iteration += 1
|
|
211
210
|
|
|
211
|
+
def restart_optimization(self, path_result: str, target_iteration: int = None) -> None:
|
|
212
|
+
|
|
213
|
+
self._load_history(path_result=path_result, target_iteration=target_iteration)
|
|
212
214
|
self.opt_loop()
|
|
213
215
|
|
|
214
216
|
def opt_loop(self) -> None:
|
|
@@ -271,26 +273,20 @@ class Controller:
|
|
|
271
273
|
self.objfun.reinitialize(iteration = self.history.iteration)
|
|
272
274
|
|
|
273
275
|
# Perform the optimization step
|
|
274
|
-
|
|
275
|
-
inp = self.params.geometry.generate()
|
|
276
|
-
self.objfun.inp = inp
|
|
277
|
-
fe = self.params.feamodel.create_fea(inp=inp)
|
|
278
|
-
self.params.materials.set_materials(fe)
|
|
279
|
-
fe.initialize()
|
|
280
|
-
self.objfun.fe = fe
|
|
276
|
+
self.objfun.fe = self.params.create_feamodel(path_result=self.path_result + '/cache/', pools=self.pools)
|
|
281
277
|
|
|
282
278
|
t1 = time.time()
|
|
283
279
|
|
|
284
280
|
# Perform finite element analysis (FEA)
|
|
285
|
-
self.objfun.
|
|
281
|
+
self.objfun.fe_results = self.solver.solve()
|
|
286
282
|
|
|
287
283
|
t2 = time.time()
|
|
288
284
|
|
|
289
|
-
#
|
|
290
|
-
self.objfun.
|
|
285
|
+
# sensitivity analysis
|
|
286
|
+
gradients = self.objfun.sensitivity_analysis(params=self.params)
|
|
291
287
|
|
|
292
288
|
# Update the surfaces based on the FEA results
|
|
293
|
-
self.updater.update()
|
|
289
|
+
self.updater.update(gradients=gradients)
|
|
294
290
|
self.updater.update_variables()
|
|
295
291
|
|
|
296
292
|
loss = self.objfun.get_objective()
|
|
@@ -307,7 +303,7 @@ class Controller:
|
|
|
307
303
|
displacement = []
|
|
308
304
|
else:
|
|
309
305
|
GC_start_index = self.objfun.fe.assembly._GC_list_indexStart[self.objfun.fe.assembly.get_reference_point('RP_head')._RGC_index]
|
|
310
|
-
displacement = [self.objfun.
|
|
306
|
+
displacement = [self.objfun.fe_results[i].GC[GC_start_index:GC_start_index+6].tolist() for i in range(self.objfun.num_tasks)]
|
|
311
307
|
self.history.append('deformation', displacement)
|
|
312
308
|
self.history.append('objective', loss.item())
|
|
313
309
|
self.history.append('metrics', self.objfun.get_metrics())
|
|
@@ -401,4 +397,43 @@ class Controller:
|
|
|
401
397
|
if isinstance(v, torch.Tensor):
|
|
402
398
|
setattr(obj, k, v.to(device))
|
|
403
399
|
else:
|
|
404
|
-
self._change_device_recursive(v, device, visited)
|
|
400
|
+
self._change_device_recursive(v, device, visited)
|
|
401
|
+
|
|
402
|
+
@classmethod
|
|
403
|
+
def _detach_recursive(cls, obj: object, visited: set=None):
|
|
404
|
+
"""
|
|
405
|
+
Recursively detach tensors to clean up the computation graph.
|
|
406
|
+
For mutable containers (list, dict, objects), replaces tensors with detached versions.
|
|
407
|
+
This avoids inplace detach_() errors on views.
|
|
408
|
+
"""
|
|
409
|
+
if visited is None:
|
|
410
|
+
visited = set()
|
|
411
|
+
|
|
412
|
+
obj_id = id(obj)
|
|
413
|
+
if obj_id in visited:
|
|
414
|
+
return
|
|
415
|
+
visited.add(obj_id)
|
|
416
|
+
|
|
417
|
+
if isinstance(obj, dict):
|
|
418
|
+
for k, v in obj.items():
|
|
419
|
+
if isinstance(v, torch.Tensor):
|
|
420
|
+
obj[k] = v.detach()
|
|
421
|
+
else:
|
|
422
|
+
cls._detach_recursive(v, visited)
|
|
423
|
+
elif isinstance(obj, list):
|
|
424
|
+
for i, v in enumerate(obj):
|
|
425
|
+
if isinstance(v, torch.Tensor):
|
|
426
|
+
obj[i] = v.detach()
|
|
427
|
+
else:
|
|
428
|
+
cls._detach_recursive(v, visited)
|
|
429
|
+
elif isinstance(obj, tuple):
|
|
430
|
+
for v in obj:
|
|
431
|
+
cls._detach_recursive(v, visited)
|
|
432
|
+
elif hasattr(obj, '__dict__'):
|
|
433
|
+
# Iterate over a copy of items to avoid modification issues
|
|
434
|
+
for k, v in list(obj.__dict__.items()):
|
|
435
|
+
if k.startswith('__'): continue
|
|
436
|
+
if isinstance(v, torch.Tensor):
|
|
437
|
+
setattr(obj, k, v.detach())
|
|
438
|
+
else:
|
|
439
|
+
cls._detach_recursive(v, visited)
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import torch
|
|
4
4
|
from ..baseobject import BaseObject
|
|
5
|
+
import torchfea
|
|
5
6
|
|
|
6
7
|
class BaseParams(BaseObject):
|
|
7
8
|
"""
|
|
@@ -11,7 +12,6 @@ class BaseParams(BaseObject):
|
|
|
11
12
|
"""
|
|
12
13
|
Initialize the parameters with the given keyword arguments.
|
|
13
14
|
"""
|
|
14
|
-
self.__dict__.update(kwargs)
|
|
15
15
|
|
|
16
16
|
def __repr__(self):
|
|
17
17
|
"""
|
|
@@ -94,4 +94,26 @@ class BaseParams(BaseObject):
|
|
|
94
94
|
Args:
|
|
95
95
|
foldpath (str): The path to export the data.
|
|
96
96
|
"""
|
|
97
|
+
pass
|
|
98
|
+
|
|
99
|
+
def obtain_design_sensitivity_vars(self, *args, **kwargs) -> torch.Tensor:
|
|
100
|
+
"""
|
|
101
|
+
Obtain the design sensitivity variables for the optimization problem.
|
|
102
|
+
|
|
103
|
+
This method should be implemented in subclasses to obtain specific design sensitivity variables.
|
|
104
|
+
|
|
105
|
+
Returns:
|
|
106
|
+
torch.Tensor: The design sensitivity variables.
|
|
107
|
+
"""
|
|
108
|
+
return torch.zeros(0)
|
|
109
|
+
|
|
110
|
+
def modify_assembly(self, design_sensitivity_vars: torch.Tensor, assembly: torchfea.Assembly) -> None:
|
|
111
|
+
"""
|
|
112
|
+
Modify the assembly for sensitivity analysis.
|
|
113
|
+
the design_sensitivity_vars will be defined in the subclasses, and the assembly will be modified according to the design_sensitivity_vars.
|
|
114
|
+
|
|
115
|
+
Args:
|
|
116
|
+
design_sensitivity_vars (torch.Tensor): The design sensitivity variables.
|
|
117
|
+
assembly (Assembly): The assembly to modify.
|
|
118
|
+
"""
|
|
97
119
|
pass
|
|
@@ -24,6 +24,8 @@ class FEAParams(BaseParams):
|
|
|
24
24
|
"""
|
|
25
25
|
Initialize the Loads class.
|
|
26
26
|
"""
|
|
27
|
+
super().__init__()
|
|
28
|
+
|
|
27
29
|
self.feainterfaces: dict[str, BaseFEAInterface] = {}
|
|
28
30
|
"""loadinterfaces (dict): A dictionary to hold the load interfaces."""
|
|
29
31
|
|
|
@@ -184,7 +186,7 @@ class FEAParams(BaseParams):
|
|
|
184
186
|
|
|
185
187
|
fe = torchfea.FEAController()
|
|
186
188
|
fe.assembly = assembly
|
|
187
|
-
fe.solver = torchfea.solver.StaticImplicitSolver(tol_error=1e-
|
|
189
|
+
fe.solver = torchfea.solver.StaticImplicitSolver(tol_error=1e-3)
|
|
188
190
|
|
|
189
191
|
# Add fea features
|
|
190
192
|
for name, interface in self.feainterfaces.items():
|