morphopt 3.1.1__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 (54) hide show
  1. morphopt-3.1.1/PKG-INFO +242 -0
  2. morphopt-3.1.1/README.md +220 -0
  3. morphopt-3.1.1/pyproject.toml +23 -0
  4. morphopt-3.1.1/setup.cfg +4 -0
  5. morphopt-3.1.1/src/morphopt/__init__.py +32 -0
  6. morphopt-3.1.1/src/morphopt/opt_runner.py +130 -0
  7. morphopt-3.1.1/src/morphopt/optcore/baseobject.py +48 -0
  8. morphopt-3.1.1/src/morphopt/optcore/controller.py +404 -0
  9. morphopt-3.1.1/src/morphopt/optcore/history.py +440 -0
  10. morphopt-3.1.1/src/morphopt/optcore/modelparams/__init__.py +4 -0
  11. morphopt-3.1.1/src/morphopt/optcore/modelparams/base_params.py +97 -0
  12. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/__init__.py +0 -0
  13. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feainterface/__init__.py +10 -0
  14. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feainterface/basefeainterface.py +50 -0
  15. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feainterface/bodyforceinterface.py +71 -0
  16. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feainterface/boundaryconditioninterface.py +59 -0
  17. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feainterface/contactinterface.py +113 -0
  18. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feainterface/coupleinterface.py +31 -0
  19. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feainterface/pointinterface.py +79 -0
  20. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feainterface/pressureinterface.py +68 -0
  21. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feainterface/referencepointinterface.py +29 -0
  22. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feainterface/springinterface.py +104 -0
  23. morphopt-3.1.1/src/morphopt/optcore/modelparams/feamodel/feaparams.py +264 -0
  24. morphopt-3.1.1/src/morphopt/optcore/modelparams/geometry/__init__.py +3 -0
  25. morphopt-3.1.1/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/__init__.py +1 -0
  26. morphopt-3.1.1/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/basesurfaceinterface.py +763 -0
  27. morphopt-3.1.1/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/bspsurfaceinterface.py +723 -0
  28. morphopt-3.1.1/src/morphopt/optcore/modelparams/geometry/geometryinterfaces/cpgeosurfaceinterface.py +374 -0
  29. morphopt-3.1.1/src/morphopt/optcore/modelparams/geometry/geometryparams.py +715 -0
  30. morphopt-3.1.1/src/morphopt/optcore/modelparams/materials/__init__.py +1 -0
  31. morphopt-3.1.1/src/morphopt/optcore/modelparams/materials/materialparams.py +110 -0
  32. morphopt-3.1.1/src/morphopt/optcore/modelparams/params.py +88 -0
  33. morphopt-3.1.1/src/morphopt/optcore/objfunc.py +248 -0
  34. morphopt-3.1.1/src/morphopt/optcore/solver.py +159 -0
  35. morphopt-3.1.1/src/morphopt/optcore/updaters/__init__.py +2 -0
  36. morphopt-3.1.1/src/morphopt/optcore/updaters/base_updater.py +110 -0
  37. morphopt-3.1.1/src/morphopt/optcore/updaters/geometry/__init__.py +2 -0
  38. morphopt-3.1.1/src/morphopt/optcore/updaters/geometry/objectivefuncs/__init__.py +5 -0
  39. morphopt-3.1.1/src/morphopt/optcore/updaters/geometry/objectivefuncs/basefuncs.py +117 -0
  40. morphopt-3.1.1/src/morphopt/optcore/updaters/geometry/objectivefuncs/boundarys.py +91 -0
  41. morphopt-3.1.1/src/morphopt/optcore/updaters/geometry/objectivefuncs/distancesurface.py +123 -0
  42. morphopt-3.1.1/src/morphopt/optcore/updaters/geometry/objectivefuncs/shapederivative.py +179 -0
  43. morphopt-3.1.1/src/morphopt/optcore/updaters/geometry/objectivefuncs/surfacefairness.py +40 -0
  44. morphopt-3.1.1/src/morphopt/optcore/updaters/geometry/update_geometry.py +347 -0
  45. morphopt-3.1.1/src/morphopt/optcore/updaters/optimizer.py +177 -0
  46. morphopt-3.1.1/src/morphopt/optcore/updaters/updaters.py +82 -0
  47. morphopt-3.1.1/src/morphopt/optcore/utils/plot_history_surface.py +239 -0
  48. morphopt-3.1.1/src/morphopt/taskoptmization.py +75 -0
  49. morphopt-3.1.1/src/morphopt/taskui.py +458 -0
  50. morphopt-3.1.1/src/morphopt.egg-info/PKG-INFO +242 -0
  51. morphopt-3.1.1/src/morphopt.egg-info/SOURCES.txt +52 -0
  52. morphopt-3.1.1/src/morphopt.egg-info/dependency_links.txt +1 -0
  53. morphopt-3.1.1/src/morphopt.egg-info/requires.txt +15 -0
  54. morphopt-3.1.1/src/morphopt.egg-info/top_level.txt +1 -0
@@ -0,0 +1,242 @@
1
+ Metadata-Version: 2.4
2
+ Name: morphopt
3
+ Version: 3.1.1
4
+ Summary: A morphing optimization framework using PyTorch and Abaqus.
5
+ Requires-Python: >=3.12
6
+ Description-Content-Type: text/markdown
7
+ Requires-Dist: torch>=2.0.0
8
+ Requires-Dist: torchvision>=0.15.1
9
+ Requires-Dist: numpy>=2.0.0
10
+ Requires-Dist: pypardiso>=0.4.7
11
+ Requires-Dist: pyqt6>=6.10.2
12
+ Requires-Dist: pyvista>=0.46.4
13
+ Requires-Dist: pyvistaqt>=0.11.3
14
+ Requires-Dist: vtk>=9.5.2
15
+ Requires-Dist: gmsh>=4.15.0
16
+ Requires-Dist: tabulate>=0.9.0
17
+ Requires-Dist: cpgeo>=1.0.2
18
+ Requires-Dist: imageio>=2.37.2
19
+ Requires-Dist: bspmap>=1.0.0
20
+ Requires-Dist: torchfea>=1.0.4
21
+ Requires-Dist: trimesh>=4.11.1
22
+
23
+ # 项目说明与使用指南
24
+
25
+ 本仓库提供基于形状优化的工作流,集成了表面参数化、有限元(FEA)求解、载荷管理与目标函数组合。你可以复用示例快速搭建新任务,或扩展接口以支持更多场景。
26
+
27
+ 目录:
28
+ - 安装与环境
29
+ - 项目结构
30
+ - 快速开始(运行示例)
31
+ - 如何定义一个优化问题(标准化工作流)
32
+ - 目标与更新器(Objective/Updater)
33
+ - 载荷接口一览(Pressure/Contact/Point)
34
+ - 日志与历史(History)
35
+ - GPU 与精度设置
36
+ - 性能建议
37
+ - 故障排查(FAQ)
38
+ - 贡献与许可证
39
+
40
+ ## 安装与环境
41
+
42
+ 前置条件:
43
+ - Python 3.10+(建议使用 conda 环境)
44
+ - Windows(已在 Windows+PowerShell 下验证),Linux 也可按需适配
45
+
46
+ 安装依赖:
47
+ ```powershell
48
+ # 可选:创建虚拟环境
49
+ conda create -n MorphOpt python=3.10 -y; conda activate MorphOpt
50
+
51
+ # 安装 Python 依赖
52
+ pip install -r requirements.txt
53
+ ```
54
+
55
+ 若使用 GPU,请确保已安装匹配的 PyTorch CUDA 版本。
56
+
57
+ ## 项目结构
58
+
59
+ 参考主要目录:
60
+ - `Jobs/`:示例与具体任务脚本(建议以 `Jobs/examples/displacement.py` 为模板)。
61
+ - `MorphOpt/`:核心库,包括参数、接口、求解器、更新器等。
62
+ - `Tests/`:简单的可视化/单元测试脚本。
63
+
64
+ 你可以在工作区面板查看完整结构。
65
+
66
+ ## 快速开始(运行示例)
67
+
68
+ 运行位移示例(displacement):
69
+ ```powershell
70
+ python Jobs/examples/displacement.py
71
+ ```
72
+
73
+ 运行其他示例(如接触/抓取/运动学等),进入对应子目录执行相应脚本。
74
+
75
+ ## 如何定义一个优化问题(标准化工作流)
76
+
77
+ 下面介绍如何在本仓库中定义一个新的优化任务。请参考并对照示例脚本 `Jobs/examples/displacement.py`。
78
+
79
+ ### 总体结构
80
+
81
+ 每个任务脚本遵循统一结构:
82
+
83
+ 1) 定义目标函数 ObjectiveFunction
84
+ - 继承自 `GLOBAL.ObjectiveFunction`,实现 `get_objective(self)`,并设置 `GLOBAL.obj_fun = ObjectiveFunction()`。
85
+
86
+ 2) 定义参数容器 Params(_Params)
87
+ - 内含三个子类:
88
+ - `SurfaceParams(_SurfacesParams)`:构建可优化的几何曲面(使用 `self.BSP.*` 初始化几何)。
89
+ - `LoadParams(_LoadsParams)`:定义“所有需要的载荷接口”和“每个加载步的幅值参数”。
90
+ - `MaterialParams(_Materials)`:设置材料参数(如 `mu`, `kappa`, `density`)。
91
+
92
+ 3) 定义 Generator、Solver、Updater 与 Controller
93
+ - `Generator(_Generator)`:生成网格/中间数据(可设置 `seed_size`, `mesh_order` 等)。
94
+ - `Solver(_MorphSolver)`:负责调用 FEA;内部会一次性将所有载荷添加到 FEA 中,并在每个加载步切换载荷“幅值”,无需重复初始化模型。
95
+ - `Updater(_Updaters)`:包含 `UpdaterSurfaces(_UpdaterSurfaces)`,在其中添加/组合优化目标项(如形状导数、平滑、边界约束等)。
96
+ - `Controller(_Controller)`:组织整个优化循环。
97
+
98
+ 4) 在 `__main__` 中初始化路径与历史、实例化各组件并执行 `controller.opt_loop()`。
99
+
100
+ ### 曲面定义 SurfaceParams
101
+
102
+ 在 `SurfaceParams` 中:
103
+ - 使用 `self.BSP.*` 工具函数构建一个或多个初始曲面,并通过 `self.add_surface(...)` 注册。
104
+ - 通过 `self.if_update = [...]` 指定哪些曲面参与更新。
105
+
106
+ 示例(略化):
107
+ ```python
108
+ class SurfaceParams(_SurfacesParams):
109
+ def __init__(self):
110
+ super().__init__(max_step_length=[0.4, 0.4])
111
+ self.add_surface(self.BSP.initialize_cylinder(r0=8., length=80., seed_size=1.0,
112
+ symmetric=[1, [1]], flip=False,
113
+ maxR=0.1, maxC=1.0, maxFF=0.2, perturbation_L=12.))
114
+ self.add_surface(self.BSP.initialize_cylinder(r0=4., length=74., seed_size=1.0,
115
+ symmetric=[1, [1]], init_location=[0, 0, 3],
116
+ flip=True, maxR=0.1, maxC=1.0, maxFF=0.2, perturbation_L=12.))
117
+ self.if_update = [True, True]
118
+ ```
119
+
120
+ ### 载荷定义 LoadParams(关键:一次定义,分步调幅)
121
+
122
+ 新的载荷定义方式遵循两个阶段:
123
+ - 阶段 A:注册“载荷接口”(仅定义类型/关联对象,不写死幅值)。
124
+ - 阶段 B:设置“步数”和“每个步的幅值”。求解时,FEA 只创建一次载荷对象,各步仅切换幅值,避免频繁重建/初始化。
125
+
126
+ LoadParams 提供以下方法:
127
+ - `add_load_interface(load_interface, name: str | None) -> str`
128
+ - 注册一个载荷接口,返回其唯一名称(若未提供 name 会自动生成)。
129
+ - `set_step_num(num_steps: int)`
130
+ - 设置加载步数量,并初始化各步的参数字典。
131
+ - `set_step_params(step_index: int, load_name: str, values: list[float])`
132
+ - 为某个加载步的某个载荷设置幅值(如压力标量,力/力矩三分量等)。
133
+
134
+ 常用载荷接口(均在 `MorphOpt/modelparams/loads/LoadInterface/` 下):
135
+ - `PressureInterface(instance_name='final_model', surface_name='...')`
136
+ - 幅值参数:`[pressure]`(单个浮点数)。
137
+ - `ConcentratedForceInterface(rp_name: str)`
138
+ - 幅值参数:`[Fx, Fy, Fz]`(三个浮点数)。
139
+ - 注意:类成员变量只存 Python list[float],不使用 torch;仅在参数导出时转为张量。
140
+ - `ConcentratedMomentInterface(rp_name: str)`
141
+ - 幅值参数:`[Mx, My, Mz]`。
142
+ - `ContactInterface(instance_name1, surface_name1, instance_name2, surface_name2, ...)`
143
+ - 接触约束,一般不需要幅值;只需注册接口即可。
144
+ - `ContactSelfInterface(instance_name, surface_name, ...)`
145
+ - 自接触约束,同样通常无幅值参数。
146
+
147
+ 示例(等价于 `Jobs/examples/displacement.py` 的写法):
148
+ ```python
149
+ class LoadParams(_LoadsParams):
150
+ def __init__(self):
151
+ super().__init__()
152
+ # A. 注册载荷接口(只定义对象,不写死幅值)
153
+ self.add_load_interface(
154
+ self.PressureInterface(instance_name='final_model', surface_name='surface_1_All'),
155
+ name='pressure_1'
156
+ )
157
+
158
+ # B. 定义步数与每步幅值
159
+ self.set_step_num(1)
160
+ self.set_step_params(0, 'pressure_1', [0.06])
161
+ ```
162
+
163
+ Solver 会在 solve 时:
164
+ - 一次性用 `get_loads_fea()` 将全部载荷添加到 FEA。
165
+ - 每个步调用 `process_fea(fea, step_index)` 应用当前步的幅值;模型不需要每步重建、仅切换数值,效率更高。
166
+
167
+ ### 材料参数 MaterialParams
168
+
169
+ 示例:
170
+ ```python
171
+ class MaterialParams(_Materials):
172
+ def __init__(self):
173
+ super().__init__(mu=0.482, kappa=4.8, density=1.08e-9)
174
+ ```
175
+
176
+ ### 生成器与求解器
177
+
178
+ - `Generator(_Generator)`:根据曲面生成中间数据;常见参数有 `seed_size`、`mesh_order` 等。
179
+ - `Solver(_MorphSolver)`:无需手动管理每步载荷添加/删除;内部已经采用“预定义载荷 + 分步调幅”的机制。
180
+
181
+ ## 目标与更新器(Objective/Updater)
182
+
183
+ 在 `Updater(_Updaters).UpdaterSurfaces(_UpdaterSurfaces)` 中:
184
+ - 创建形状导数(如 `ShapeDerivativeDirect(reset_per_iter=5)`)并注册:
185
+ - `self.add_objective_function(shape_derivative)`
186
+ - 可叠加其它目标/正则(如 `Fairness`, `Distance`, `boundarys.Cylinder` 等)。
187
+
188
+ 常见用法:
189
+ - 目标函数统一通过 `self.add_objective_function(...)` 注册。
190
+ - 多目标时,可通过权重在对应目标构造参数中体现。
191
+
192
+ ## 载荷接口一览(Pressure/Contact/Point)
193
+
194
+ 位置:`MorphOpt/modelparams/loads/LoadInterface/`
195
+
196
+ - PressureInterface:面压力,单一标量幅值。
197
+ - ContactInterface:外部接触;一般无幅值。
198
+ - ContactSelfInterface:自接触;一般无幅值。
199
+ - ConcentratedForceInterface:集中力,基于参考点名 `rp_name`,幅值为 `[Fx,Fy,Fz]`。
200
+ - ConcentratedMomentInterface:集中力矩,`rp_name`,幅值为 `[Mx,My,Mz]`。
201
+ - SpringToGroundInterface:弹簧(RP-地面点),参数顺序为 `[k, L0, Px, Py, Pz]`。
202
+ - SpringBetweenRPsInterface:弹簧(RP-RP),参数顺序为 `[k, L0]`。
203
+
204
+ 注意:接口类内部仅存 Python list[float];参数导出阶段再转为张量,便于优化器统一打包。
205
+
206
+ ## 日志与历史(History)
207
+
208
+ - `initializer.initialize_path(...)` 会创建输出目录结构(如 `Results/`)。
209
+ - `initializer.initialize_history()` 管理迭代历史(`GLOBAL.History`)。
210
+ - 你可以在 `Jobs/...` 的脚本中设置任务名与输出路径,以便归档每次试验结果。
211
+
212
+ ## GPU 与精度设置
213
+
214
+ - 默认使用 `torch.float64`;可在入口脚本中通过 `torch.set_default_dtype` 调整。
215
+ - 若可用 GPU,则内部会选择合适设备;也可在脚本中手动设置或屏蔽 CUDA(调试时可启用 `CUDA_LAUNCH_BLOCKING=1`)。
216
+
217
+ ## 性能建议
218
+
219
+ - 预先“注册所有载荷”,并仅在步间切换幅值(已在 `LoadParams`/`Solver` 内实现)。
220
+ - 合理设置网格密度与曲面参数,避免过大规模导致 FEA 迭代缓慢。
221
+ - 多步求解时,确保每步仅修改必要的幅值,减少 FE 内部对象的重复构建。
222
+
223
+ ## 故障排查(FAQ)
224
+
225
+ - 载荷无效/不生效?
226
+ - 确认已通过 `add_load_interface` 注册;对有幅值的载荷在每个步都正确调用了 `set_step_params`。
227
+ - 接触相关错误?
228
+ - 检查实例名与表面名是否与 INP/几何一致;必要时在 `Solver.init_FEA` 中自定义接触参数。
229
+ - GPU/精度导致的数值不稳定?
230
+ - 可改回 CPU 或降低步长;确保所有张量 dtype 一致为 float64。
231
+
232
+ ## 贡献与许可证
233
+
234
+ - 欢迎通过 PR/Issue 贡献新的载荷接口、目标函数或示例任务。
235
+ - 许可证与版权信息请参考仓库根目录中的相关文件(若缺失,请在提交 PR 时补充)。
236
+
237
+ ---
238
+
239
+ 更多参考:
240
+ - 示例:`Jobs/examples/displacement.py`
241
+ - 接触/集中载荷用法:`Jobs/locomotion/front.py`、`Jobs/ral2025contact/*`
242
+ - 载荷接口实现:`MorphOpt/modelparams/loads/LoadInterface/`
@@ -0,0 +1,220 @@
1
+ # 项目说明与使用指南
2
+
3
+ 本仓库提供基于形状优化的工作流,集成了表面参数化、有限元(FEA)求解、载荷管理与目标函数组合。你可以复用示例快速搭建新任务,或扩展接口以支持更多场景。
4
+
5
+ 目录:
6
+ - 安装与环境
7
+ - 项目结构
8
+ - 快速开始(运行示例)
9
+ - 如何定义一个优化问题(标准化工作流)
10
+ - 目标与更新器(Objective/Updater)
11
+ - 载荷接口一览(Pressure/Contact/Point)
12
+ - 日志与历史(History)
13
+ - GPU 与精度设置
14
+ - 性能建议
15
+ - 故障排查(FAQ)
16
+ - 贡献与许可证
17
+
18
+ ## 安装与环境
19
+
20
+ 前置条件:
21
+ - Python 3.10+(建议使用 conda 环境)
22
+ - Windows(已在 Windows+PowerShell 下验证),Linux 也可按需适配
23
+
24
+ 安装依赖:
25
+ ```powershell
26
+ # 可选:创建虚拟环境
27
+ conda create -n MorphOpt python=3.10 -y; conda activate MorphOpt
28
+
29
+ # 安装 Python 依赖
30
+ pip install -r requirements.txt
31
+ ```
32
+
33
+ 若使用 GPU,请确保已安装匹配的 PyTorch CUDA 版本。
34
+
35
+ ## 项目结构
36
+
37
+ 参考主要目录:
38
+ - `Jobs/`:示例与具体任务脚本(建议以 `Jobs/examples/displacement.py` 为模板)。
39
+ - `MorphOpt/`:核心库,包括参数、接口、求解器、更新器等。
40
+ - `Tests/`:简单的可视化/单元测试脚本。
41
+
42
+ 你可以在工作区面板查看完整结构。
43
+
44
+ ## 快速开始(运行示例)
45
+
46
+ 运行位移示例(displacement):
47
+ ```powershell
48
+ python Jobs/examples/displacement.py
49
+ ```
50
+
51
+ 运行其他示例(如接触/抓取/运动学等),进入对应子目录执行相应脚本。
52
+
53
+ ## 如何定义一个优化问题(标准化工作流)
54
+
55
+ 下面介绍如何在本仓库中定义一个新的优化任务。请参考并对照示例脚本 `Jobs/examples/displacement.py`。
56
+
57
+ ### 总体结构
58
+
59
+ 每个任务脚本遵循统一结构:
60
+
61
+ 1) 定义目标函数 ObjectiveFunction
62
+ - 继承自 `GLOBAL.ObjectiveFunction`,实现 `get_objective(self)`,并设置 `GLOBAL.obj_fun = ObjectiveFunction()`。
63
+
64
+ 2) 定义参数容器 Params(_Params)
65
+ - 内含三个子类:
66
+ - `SurfaceParams(_SurfacesParams)`:构建可优化的几何曲面(使用 `self.BSP.*` 初始化几何)。
67
+ - `LoadParams(_LoadsParams)`:定义“所有需要的载荷接口”和“每个加载步的幅值参数”。
68
+ - `MaterialParams(_Materials)`:设置材料参数(如 `mu`, `kappa`, `density`)。
69
+
70
+ 3) 定义 Generator、Solver、Updater 与 Controller
71
+ - `Generator(_Generator)`:生成网格/中间数据(可设置 `seed_size`, `mesh_order` 等)。
72
+ - `Solver(_MorphSolver)`:负责调用 FEA;内部会一次性将所有载荷添加到 FEA 中,并在每个加载步切换载荷“幅值”,无需重复初始化模型。
73
+ - `Updater(_Updaters)`:包含 `UpdaterSurfaces(_UpdaterSurfaces)`,在其中添加/组合优化目标项(如形状导数、平滑、边界约束等)。
74
+ - `Controller(_Controller)`:组织整个优化循环。
75
+
76
+ 4) 在 `__main__` 中初始化路径与历史、实例化各组件并执行 `controller.opt_loop()`。
77
+
78
+ ### 曲面定义 SurfaceParams
79
+
80
+ 在 `SurfaceParams` 中:
81
+ - 使用 `self.BSP.*` 工具函数构建一个或多个初始曲面,并通过 `self.add_surface(...)` 注册。
82
+ - 通过 `self.if_update = [...]` 指定哪些曲面参与更新。
83
+
84
+ 示例(略化):
85
+ ```python
86
+ class SurfaceParams(_SurfacesParams):
87
+ def __init__(self):
88
+ super().__init__(max_step_length=[0.4, 0.4])
89
+ self.add_surface(self.BSP.initialize_cylinder(r0=8., length=80., seed_size=1.0,
90
+ symmetric=[1, [1]], flip=False,
91
+ maxR=0.1, maxC=1.0, maxFF=0.2, perturbation_L=12.))
92
+ self.add_surface(self.BSP.initialize_cylinder(r0=4., length=74., seed_size=1.0,
93
+ symmetric=[1, [1]], init_location=[0, 0, 3],
94
+ flip=True, maxR=0.1, maxC=1.0, maxFF=0.2, perturbation_L=12.))
95
+ self.if_update = [True, True]
96
+ ```
97
+
98
+ ### 载荷定义 LoadParams(关键:一次定义,分步调幅)
99
+
100
+ 新的载荷定义方式遵循两个阶段:
101
+ - 阶段 A:注册“载荷接口”(仅定义类型/关联对象,不写死幅值)。
102
+ - 阶段 B:设置“步数”和“每个步的幅值”。求解时,FEA 只创建一次载荷对象,各步仅切换幅值,避免频繁重建/初始化。
103
+
104
+ LoadParams 提供以下方法:
105
+ - `add_load_interface(load_interface, name: str | None) -> str`
106
+ - 注册一个载荷接口,返回其唯一名称(若未提供 name 会自动生成)。
107
+ - `set_step_num(num_steps: int)`
108
+ - 设置加载步数量,并初始化各步的参数字典。
109
+ - `set_step_params(step_index: int, load_name: str, values: list[float])`
110
+ - 为某个加载步的某个载荷设置幅值(如压力标量,力/力矩三分量等)。
111
+
112
+ 常用载荷接口(均在 `MorphOpt/modelparams/loads/LoadInterface/` 下):
113
+ - `PressureInterface(instance_name='final_model', surface_name='...')`
114
+ - 幅值参数:`[pressure]`(单个浮点数)。
115
+ - `ConcentratedForceInterface(rp_name: str)`
116
+ - 幅值参数:`[Fx, Fy, Fz]`(三个浮点数)。
117
+ - 注意:类成员变量只存 Python list[float],不使用 torch;仅在参数导出时转为张量。
118
+ - `ConcentratedMomentInterface(rp_name: str)`
119
+ - 幅值参数:`[Mx, My, Mz]`。
120
+ - `ContactInterface(instance_name1, surface_name1, instance_name2, surface_name2, ...)`
121
+ - 接触约束,一般不需要幅值;只需注册接口即可。
122
+ - `ContactSelfInterface(instance_name, surface_name, ...)`
123
+ - 自接触约束,同样通常无幅值参数。
124
+
125
+ 示例(等价于 `Jobs/examples/displacement.py` 的写法):
126
+ ```python
127
+ class LoadParams(_LoadsParams):
128
+ def __init__(self):
129
+ super().__init__()
130
+ # A. 注册载荷接口(只定义对象,不写死幅值)
131
+ self.add_load_interface(
132
+ self.PressureInterface(instance_name='final_model', surface_name='surface_1_All'),
133
+ name='pressure_1'
134
+ )
135
+
136
+ # B. 定义步数与每步幅值
137
+ self.set_step_num(1)
138
+ self.set_step_params(0, 'pressure_1', [0.06])
139
+ ```
140
+
141
+ Solver 会在 solve 时:
142
+ - 一次性用 `get_loads_fea()` 将全部载荷添加到 FEA。
143
+ - 每个步调用 `process_fea(fea, step_index)` 应用当前步的幅值;模型不需要每步重建、仅切换数值,效率更高。
144
+
145
+ ### 材料参数 MaterialParams
146
+
147
+ 示例:
148
+ ```python
149
+ class MaterialParams(_Materials):
150
+ def __init__(self):
151
+ super().__init__(mu=0.482, kappa=4.8, density=1.08e-9)
152
+ ```
153
+
154
+ ### 生成器与求解器
155
+
156
+ - `Generator(_Generator)`:根据曲面生成中间数据;常见参数有 `seed_size`、`mesh_order` 等。
157
+ - `Solver(_MorphSolver)`:无需手动管理每步载荷添加/删除;内部已经采用“预定义载荷 + 分步调幅”的机制。
158
+
159
+ ## 目标与更新器(Objective/Updater)
160
+
161
+ 在 `Updater(_Updaters).UpdaterSurfaces(_UpdaterSurfaces)` 中:
162
+ - 创建形状导数(如 `ShapeDerivativeDirect(reset_per_iter=5)`)并注册:
163
+ - `self.add_objective_function(shape_derivative)`
164
+ - 可叠加其它目标/正则(如 `Fairness`, `Distance`, `boundarys.Cylinder` 等)。
165
+
166
+ 常见用法:
167
+ - 目标函数统一通过 `self.add_objective_function(...)` 注册。
168
+ - 多目标时,可通过权重在对应目标构造参数中体现。
169
+
170
+ ## 载荷接口一览(Pressure/Contact/Point)
171
+
172
+ 位置:`MorphOpt/modelparams/loads/LoadInterface/`
173
+
174
+ - PressureInterface:面压力,单一标量幅值。
175
+ - ContactInterface:外部接触;一般无幅值。
176
+ - ContactSelfInterface:自接触;一般无幅值。
177
+ - ConcentratedForceInterface:集中力,基于参考点名 `rp_name`,幅值为 `[Fx,Fy,Fz]`。
178
+ - ConcentratedMomentInterface:集中力矩,`rp_name`,幅值为 `[Mx,My,Mz]`。
179
+ - SpringToGroundInterface:弹簧(RP-地面点),参数顺序为 `[k, L0, Px, Py, Pz]`。
180
+ - SpringBetweenRPsInterface:弹簧(RP-RP),参数顺序为 `[k, L0]`。
181
+
182
+ 注意:接口类内部仅存 Python list[float];参数导出阶段再转为张量,便于优化器统一打包。
183
+
184
+ ## 日志与历史(History)
185
+
186
+ - `initializer.initialize_path(...)` 会创建输出目录结构(如 `Results/`)。
187
+ - `initializer.initialize_history()` 管理迭代历史(`GLOBAL.History`)。
188
+ - 你可以在 `Jobs/...` 的脚本中设置任务名与输出路径,以便归档每次试验结果。
189
+
190
+ ## GPU 与精度设置
191
+
192
+ - 默认使用 `torch.float64`;可在入口脚本中通过 `torch.set_default_dtype` 调整。
193
+ - 若可用 GPU,则内部会选择合适设备;也可在脚本中手动设置或屏蔽 CUDA(调试时可启用 `CUDA_LAUNCH_BLOCKING=1`)。
194
+
195
+ ## 性能建议
196
+
197
+ - 预先“注册所有载荷”,并仅在步间切换幅值(已在 `LoadParams`/`Solver` 内实现)。
198
+ - 合理设置网格密度与曲面参数,避免过大规模导致 FEA 迭代缓慢。
199
+ - 多步求解时,确保每步仅修改必要的幅值,减少 FE 内部对象的重复构建。
200
+
201
+ ## 故障排查(FAQ)
202
+
203
+ - 载荷无效/不生效?
204
+ - 确认已通过 `add_load_interface` 注册;对有幅值的载荷在每个步都正确调用了 `set_step_params`。
205
+ - 接触相关错误?
206
+ - 检查实例名与表面名是否与 INP/几何一致;必要时在 `Solver.init_FEA` 中自定义接触参数。
207
+ - GPU/精度导致的数值不稳定?
208
+ - 可改回 CPU 或降低步长;确保所有张量 dtype 一致为 float64。
209
+
210
+ ## 贡献与许可证
211
+
212
+ - 欢迎通过 PR/Issue 贡献新的载荷接口、目标函数或示例任务。
213
+ - 许可证与版权信息请参考仓库根目录中的相关文件(若缺失,请在提交 PR 时补充)。
214
+
215
+ ---
216
+
217
+ 更多参考:
218
+ - 示例:`Jobs/examples/displacement.py`
219
+ - 接触/集中载荷用法:`Jobs/locomotion/front.py`、`Jobs/ral2025contact/*`
220
+ - 载荷接口实现:`MorphOpt/modelparams/loads/LoadInterface/`
@@ -0,0 +1,23 @@
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
+ ]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,32 @@
1
+ # region optcore imports
2
+ from .optcore.controller import Controller
3
+ from .optcore.modelparams import GeometryParams, FEAParams, Materials
4
+ from .optcore.solver import MorphSolver
5
+ from .optcore.updaters.geometry import UpdaterGeometries
6
+ from .optcore.updaters.updaters import Updaters
7
+ from .optcore.modelparams import Params
8
+ from .optcore.objfunc import ObjectiveFunction
9
+ from .optcore.history import History
10
+ from .optcore.baseobject import BaseObject
11
+ from .optcore.utils.plot_history_surface import SurfacesFigurePlotter
12
+ # endregion
13
+
14
+ from .opt_runner import start_optimization, debug_optimization, view_optimization_result
15
+
16
+
17
+
18
+
19
+ controller: Controller = None
20
+
21
+ __all__ = [
22
+ "Controller",
23
+ "GeometryParams",
24
+ "FEAParams",
25
+ "Materials",
26
+ "MorphSolver",
27
+ "UpdaterGeometries",
28
+ "Updaters",
29
+ "Params",
30
+ "ObjectiveFunction",
31
+ ]
32
+
@@ -0,0 +1,130 @@
1
+
2
+
3
+
4
+ def start_optimization(device='cpu', restart_per_iteration: int = 20, path_result: str=None, target_iteration=None, no_gui: bool=False):
5
+ """
6
+ Start a new optimization process.
7
+
8
+ Args:
9
+ Controller (type): The controller class to use for the optimization.
10
+ device (str, optional): The device to use for computation. Defaults to 'cpu'.
11
+ restart_per_iteration (int, optional): The number of iterations between restarts. Defaults to 20.
12
+ """
13
+ if path_result is None:
14
+ import __main__
15
+ main_filepath = __main__.__file__
16
+ else:
17
+ main_filepath = path_result + '/scripts/' + 'MAIN_SCRIPT_FOR_RESTART.py'
18
+
19
+ import time
20
+ import multiprocessing as mp
21
+ from .taskoptmization import TaskOptimization
22
+ from .taskui import run_ui
23
+
24
+
25
+ dataqueue = mp.Queue()
26
+ process_optimization = mp.Process(target=TaskOptimization.task_optimization, kwargs={'path_result': path_result,
27
+ 'main_filepath': main_filepath,
28
+ 'device': device,
29
+ 'target_iteration': target_iteration,
30
+ 'restart_per_iteration': restart_per_iteration,
31
+ 'dataqueue': dataqueue})
32
+ process_optimization.start()
33
+
34
+ if no_gui:
35
+ process_optimization.join()
36
+ return
37
+
38
+ process_ui = mp.Process(target=run_ui, args=(dataqueue, main_filepath))
39
+ process_ui.start()
40
+
41
+ process_optimization.join()
42
+ process_ui.join()
43
+
44
+ def view_optimization_result(path_result: str = None):
45
+ """
46
+ View the result of an optimization process.
47
+
48
+ Args:
49
+ path_result (str): The folder path of the optimization result.
50
+ """
51
+ import os
52
+ import multiprocessing as mp
53
+ from .taskui import run_ui
54
+ from .optcore.history import History
55
+
56
+ if path_result is None or not os.path.exists(path_result):
57
+ # Use file dialog to select directory if path is not provided
58
+ # We need a temporary app to show the dialog
59
+ from PyQt6.QtWidgets import QApplication, QFileDialog
60
+ import sys
61
+
62
+ # Check if an app instance already exists
63
+ app = QApplication.instance()
64
+ if not app:
65
+ app = QApplication(sys.argv)
66
+
67
+ path_result = QFileDialog.getExistingDirectory(None, "Select Optimization Result Folder", os.getcwd())
68
+ if not path_result:
69
+ return
70
+
71
+ main_filepath = os.path.join(path_result, 'scripts', 'MAIN_SCRIPT_FOR_RESTART.py')
72
+ if not os.path.exists(main_filepath):
73
+ print(f"Error: {main_filepath} not found.")
74
+ return
75
+
76
+ # Determine the last iteration
77
+ history = History()
78
+ try:
79
+ history.load(foldpath=os.path.join(path_result, 'log'))
80
+ last_iteration = history.iteration
81
+ except:
82
+ last_iteration = 0
83
+
84
+ dataqueue = mp.Queue()
85
+ # Send the initial data to load the result
86
+ dataqueue.put({'iteration': last_iteration, 'path_result': path_result})
87
+
88
+ run_ui(dataqueue, main_filepath)
89
+
90
+ def debug_optimization(device='cpu', restart_per_iteration: int = 20, path_result: str=None, target_iteration=None, ):
91
+ """
92
+ Start a new optimization process.
93
+
94
+ Args:
95
+ Controller (type): The controller class to use for the optimization.
96
+ device (str, optional): The device to use for computation. Defaults to 'cpu'.
97
+ restart_per_iteration (int, optional): The number of iterations between restarts. Defaults to 20.
98
+ """
99
+ import __main__
100
+ from .taskoptmization import TaskOptimization
101
+ import os
102
+ import morphopt
103
+
104
+ if path_result is None:
105
+ import __main__
106
+ main_filepath = __main__.__file__
107
+ else:
108
+ main_filepath = path_result + '/scripts/' + 'MAIN_SCRIPT_FOR_RESTART.py'
109
+
110
+ filename = os.path.splitext(os.path.basename(main_filepath))[0]
111
+ filepath = os.path.dirname(main_filepath)
112
+ os.chdir(filepath)
113
+ import sys
114
+ sys.path.append(os.getcwd())
115
+
116
+ Controller: morphopt.Controller = getattr(__import__(filename), 'ThisController')
117
+
118
+ controller: morphopt.Controller = Controller()
119
+ controller.restart_per_iteration = restart_per_iteration
120
+ controller.optdevice = device
121
+
122
+ TaskOptimization.optmain(device=device,
123
+ path_result=path_result,
124
+ target_iteration=target_iteration,
125
+ restart_per_iteration=restart_per_iteration,
126
+ main_filepath=main_filepath)
127
+
128
+
129
+
130
+