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.
Files changed (66) hide show
  1. {morphopt-3.1.1 → morphopt-3.1.2}/PKG-INFO +33 -9
  2. {morphopt-3.1.1 → morphopt-3.1.2}/README.md +23 -1
  3. {morphopt-3.1.1 → morphopt-3.1.2}/pyproject.toml +25 -23
  4. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/__init__.py +3 -2
  5. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/controller.py +50 -15
  6. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/__init__.py +1 -1
  7. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/base_params.py +23 -1
  8. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feaparams.py +3 -1
  9. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/basesurfaceinterface.py +169 -36
  10. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/bspsurfaceinterface.py +229 -65
  11. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/cpgeosurfaceinterface.py +200 -51
  12. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/geometryparams.py +57 -22
  13. morphopt-3.1.2/src/morphopt/optcore/modelparams/materials/__init__.py +3 -0
  14. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/materials/materialparams.py +0 -11
  15. morphopt-3.1.2/src/morphopt/optcore/modelparams/materials/simpmaterial.py +430 -0
  16. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/params.py +52 -1
  17. morphopt-3.1.2/src/morphopt/optcore/objfunc.py +273 -0
  18. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/solver.py +10 -7
  19. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/__init__.py +1 -0
  20. morphopt-3.1.2/src/morphopt/optcore/updaters/geometry/objectivefuncs/__init__.py +5 -0
  21. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/objectivefuncs/basefuncs.py +4 -5
  22. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/objectivefuncs/distancesurface.py +1 -1
  23. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/objectivefuncs/shapederivative.py +55 -36
  24. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/objectivefuncs/surfacefairness.py +4 -4
  25. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/update_geometry.py +9 -9
  26. morphopt-3.1.2/src/morphopt/optcore/updaters/materials/__init__.py +1 -0
  27. morphopt-3.1.2/src/morphopt/optcore/updaters/materials/objectivefuncs/__init__.py +12 -0
  28. morphopt-3.1.2/src/morphopt/optcore/updaters/materials/objectivefuncs/basefuncs.py +112 -0
  29. morphopt-3.1.2/src/morphopt/optcore/updaters/materials/objectivefuncs/boundarys.py +71 -0
  30. morphopt-3.1.2/src/morphopt/optcore/updaters/materials/objectivefuncs/densityfield.py +25 -0
  31. morphopt-3.1.2/src/morphopt/optcore/updaters/materials/objectivefuncs/sensitivity.py +32 -0
  32. morphopt-3.1.2/src/morphopt/optcore/updaters/materials/update_material.py +338 -0
  33. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/updaters.py +37 -4
  34. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/taskui.py +11 -9
  35. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt.egg-info/PKG-INFO +33 -9
  36. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt.egg-info/SOURCES.txt +8 -1
  37. morphopt-3.1.2/src/morphopt.egg-info/requires.txt +17 -0
  38. morphopt-3.1.1/src/morphopt/optcore/modelparams/materials/__init__.py +0 -1
  39. morphopt-3.1.1/src/morphopt/optcore/objfunc.py +0 -248
  40. morphopt-3.1.1/src/morphopt/optcore/updaters/geometry/objectivefuncs/__init__.py +0 -5
  41. morphopt-3.1.1/src/morphopt/optcore/utils/plot_history_surface.py +0 -239
  42. morphopt-3.1.1/src/morphopt.egg-info/requires.txt +0 -15
  43. {morphopt-3.1.1 → morphopt-3.1.2}/setup.cfg +0 -0
  44. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/opt_runner.py +0 -0
  45. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/baseobject.py +0 -0
  46. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/history.py +0 -0
  47. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/__init__.py +0 -0
  48. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/__init__.py +0 -0
  49. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/basefeainterface.py +0 -0
  50. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/bodyforceinterface.py +0 -0
  51. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/boundaryconditioninterface.py +0 -0
  52. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/contactinterface.py +0 -0
  53. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/coupleinterface.py +0 -0
  54. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/pointinterface.py +0 -0
  55. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/pressureinterface.py +0 -0
  56. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/referencepointinterface.py +0 -0
  57. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/feamodel/feainterface/springinterface.py +0 -0
  58. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/__init__.py +0 -0
  59. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/__init__.py +0 -0
  60. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/base_updater.py +0 -0
  61. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/__init__.py +0 -0
  62. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/geometry/objectivefuncs/boundarys.py +0 -0
  63. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/optcore/updaters/optimizer.py +0 -0
  64. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt/taskoptmization.py +0 -0
  65. {morphopt-3.1.1 → morphopt-3.1.2}/src/morphopt.egg-info/dependency_links.txt +0 -0
  66. {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.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.10.2
12
- Requires-Dist: pyvista>=0.46.4
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.5.2
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: cpgeo>=1.0.2
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.4
21
- Requires-Dist: trimesh>=4.11.1
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
- - 继承自 `GLOBAL.ObjectiveFunction`,实现 `get_objective(self)`,并设置 `GLOBAL.obj_fun = ObjectiveFunction()`。
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
- - 继承自 `GLOBAL.ObjectiveFunction`,实现 `get_objective(self)`,并设置 `GLOBAL.obj_fun = ObjectiveFunction()`。
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.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.10.2",
13
- "pyvista>=0.46.4",
14
- "pyvistaqt>=0.11.3",
15
- "vtk>=9.5.2",
16
- "gmsh>=4.15.0",
17
- "tabulate>=0.9.0",
18
- "cpgeo>=1.0.2",
19
- "imageio>=2.37.2",
20
- "bspmap>=1.0.0",
21
- "torchfea>=1.0.4",
22
- "trimesh>=4.11.1",
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 restart_optimization(self, path_result: str, target_iteration: int = None) -> None:
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
- # Generate the model
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.U = self.solver.solve()
281
+ self.objfun.fe_results = self.solver.solve()
286
282
 
287
283
  t2 = time.time()
288
284
 
289
- # the adjoint problem
290
- self.objfun.calculate_adjoint_problem()
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.U[i][GC_start_index:GC_start_index+6].tolist() for i in range(len(self.objfun.U))]
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)
@@ -1,4 +1,4 @@
1
1
  from .geometry.geometryparams import GeometryParams
2
2
  from .feamodel.feaparams import FEAParams
3
- from .materials.materialparams import Materials
3
+ from .materials import Materials, SIMPMaterials
4
4
  from .params import Params
@@ -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-6)
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():