morphopt 3.1.5__tar.gz → 3.2.0__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.

Potentially problematic release.


This version of morphopt might be problematic. Click here for more details.

Files changed (112) hide show
  1. morphopt-3.2.0/PKG-INFO +151 -0
  2. morphopt-3.2.0/README.md +127 -0
  3. {morphopt-3.1.5 → morphopt-3.2.0}/pyproject.toml +7 -3
  4. {morphopt-3.1.5 → morphopt-3.2.0}/setup.cfg +0 -0
  5. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/__init__.py +1 -1
  6. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/codesign/feaparams.py +2 -2
  7. morphopt-3.2.0/src/morphopt/opt_runner.py +82 -0
  8. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/geometry.py +5 -3
  9. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/geometryinterfaces/basesurfaceinterface.py +1 -23
  10. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/geometryinterfaces/bspsurfaceinterface.py +5 -10
  11. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/geometryinterfaces/cpgeosurfaceinterface.py +6 -8
  12. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/geometryparams.py +4 -3
  13. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/objectivefuncs/distancesurface.py +0 -0
  14. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/objectivefuncs/shapederivative.py +0 -0
  15. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/taskoptmization.py +18 -23
  16. morphopt-3.2.0/src/morphopt/ui/__init__.py +38 -0
  17. morphopt-3.2.0/src/morphopt/ui/__main__.py +6 -0
  18. morphopt-3.2.0/src/morphopt/ui/app.py +64 -0
  19. morphopt-3.2.0/src/morphopt/ui/codegen/__init__.py +1 -0
  20. morphopt-3.2.0/src/morphopt/ui/codegen/generator.py +431 -0
  21. morphopt-3.2.0/src/morphopt/ui/i18n.py +74 -0
  22. morphopt-3.2.0/src/morphopt/ui/launcher.py +216 -0
  23. morphopt-3.2.0/src/morphopt/ui/mainwindow.py +209 -0
  24. morphopt-3.2.0/src/morphopt/ui/model/__init__.py +16 -0
  25. morphopt-3.2.0/src/morphopt/ui/model/loaders.py +32 -0
  26. morphopt-3.2.0/src/morphopt/ui/model/problem.py +1069 -0
  27. morphopt-3.2.0/src/morphopt/ui/model/schemas.py +797 -0
  28. morphopt-3.2.0/src/morphopt/ui/observe_panel.py +968 -0
  29. morphopt-3.2.0/src/morphopt/ui/schemes/__init__.py +18 -0
  30. morphopt-3.2.0/src/morphopt/ui/schemes/base.py +186 -0
  31. morphopt-3.2.0/src/morphopt/ui/schemes/codesign.py +143 -0
  32. morphopt-3.2.0/src/morphopt/ui/schemes/shapeopt.py +100 -0
  33. morphopt-3.2.0/src/morphopt/ui/schemes/simp.py +96 -0
  34. morphopt-3.2.0/src/morphopt/ui/schemes/snippets.py +236 -0
  35. morphopt-3.2.0/src/morphopt/ui/widgets/__init__.py +1 -0
  36. morphopt-3.2.0/src/morphopt/ui/widgets/code_completion.py +180 -0
  37. morphopt-3.2.0/src/morphopt/ui/widgets/codeeditor.py +372 -0
  38. morphopt-3.2.0/src/morphopt/ui/widgets/editor.py +322 -0
  39. morphopt-3.2.0/src/morphopt/ui/widgets/model_tree.py +485 -0
  40. morphopt-3.2.0/src/morphopt/ui/widgets/objective_editor.py +233 -0
  41. morphopt-3.2.0/src/morphopt/ui/widgets/observation_pages.py +246 -0
  42. morphopt-3.2.0/src/morphopt/ui/widgets/param_form.py +159 -0
  43. morphopt-3.2.0/src/morphopt/ui/widgets/solver_editor.py +187 -0
  44. morphopt-3.2.0/src/morphopt/ui/widgets/stepmatrix.py +226 -0
  45. morphopt-3.2.0/src/morphopt/ui/widgets/template_insert_dialog.py +198 -0
  46. morphopt-3.2.0/src/morphopt/ui/widgets/updater_editor.py +699 -0
  47. morphopt-3.2.0/src/morphopt/ui/widgets/values.py +86 -0
  48. morphopt-3.2.0/src/morphopt/ui/widgets/viewer.py +277 -0
  49. morphopt-3.2.0/src/morphopt/ui/workbench.py +506 -0
  50. morphopt-3.2.0/src/morphopt.egg-info/PKG-INFO +151 -0
  51. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt.egg-info/SOURCES.txt +35 -1
  52. morphopt-3.2.0/src/morphopt.egg-info/entry_points.txt +2 -0
  53. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt.egg-info/requires.txt +2 -2
  54. {morphopt-3.1.5 → morphopt-3.2.0}/tests/test_ui.py +0 -0
  55. morphopt-3.1.5/PKG-INFO +0 -82
  56. morphopt-3.1.5/README.md +0 -58
  57. morphopt-3.1.5/src/morphopt/opt_runner.py +0 -143
  58. morphopt-3.1.5/src/morphopt/taskui.py +0 -494
  59. morphopt-3.1.5/src/morphopt.egg-info/PKG-INFO +0 -82
  60. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/codesign/__init__.py +0 -0
  61. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/codesign/constraints.py +0 -0
  62. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/codesign/geometry.py +0 -0
  63. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/codesign/material.py +0 -0
  64. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/codesign/params.py +0 -0
  65. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/__init__.py +0 -0
  66. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/baseobject.py +0 -0
  67. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/controller.py +0 -0
  68. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/history.py +0 -0
  69. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/__init__.py +0 -0
  70. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/baseparam.py +0 -0
  71. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feainterface/__init__.py +0 -0
  72. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feainterface/basefeainterface.py +0 -0
  73. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feainterface/bodyforceinterface.py +0 -0
  74. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feainterface/boundaryconditioninterface.py +0 -0
  75. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feainterface/contactinterface.py +0 -0
  76. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feainterface/coupleinterface.py +0 -0
  77. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feainterface/pointinterface.py +0 -0
  78. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feainterface/pressureinterface.py +0 -0
  79. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feainterface/referencepointinterface.py +0 -0
  80. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feainterface/springinterface.py +0 -0
  81. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/feaparams.py +0 -0
  82. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/materials.py +0 -0
  83. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/modelparams/params.py +0 -0
  84. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/objfunc.py +0 -0
  85. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/solver.py +0 -0
  86. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/optcore/updaters.py +0 -0
  87. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/__init__.py +0 -0
  88. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/geometryinterfaces/__init__.py +0 -0
  89. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/objectivefuncs/__init__.py +0 -0
  90. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/objectivefuncs/basefuncs.py +0 -0
  91. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/objectivefuncs/boundarys.py +0 -0
  92. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/objectivefuncs/surfacefairness.py +0 -0
  93. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/objectivefuncs/volumemaximization.py +0 -0
  94. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/objfunc.py +0 -0
  95. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/shapeopt/update_geometry.py +0 -0
  96. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/simp/__init__.py +0 -0
  97. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/simp/objectivefuncs/__init__.py +0 -0
  98. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/simp/objectivefuncs/basefuncs.py +0 -0
  99. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/simp/objectivefuncs/boundarys.py +0 -0
  100. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/simp/objectivefuncs/densityfield.py +0 -0
  101. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/simp/objectivefuncs/sensitivity.py +0 -0
  102. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/simp/objectivefuncs/volfrac.py +0 -0
  103. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/simp/simpmaterial.py +0 -0
  104. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/simp/solver.py +0 -0
  105. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/simp/update_material.py +0 -0
  106. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/utils/__init__.py +0 -0
  107. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/utils/gradient_check.py +0 -0
  108. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt/utils/history_read.py +0 -0
  109. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt.egg-info/dependency_links.txt +0 -0
  110. {morphopt-3.1.5 → morphopt-3.2.0}/src/morphopt.egg-info/top_level.txt +0 -0
  111. {morphopt-3.1.5 → morphopt-3.2.0}/tests/test_fixedGeometry.py +0 -0
  112. {morphopt-3.1.5 → morphopt-3.2.0}/tests/test_path.py +0 -0
@@ -0,0 +1,151 @@
1
+ Metadata-Version: 2.4
2
+ Name: morphopt
3
+ Version: 3.2.0
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.9.1
8
+ Requires-Dist: torchvision>=0.15.1
9
+ Requires-Dist: numpy>=2.0.0
10
+ Requires-Dist: pypardiso>=0.4.7
11
+ Requires-Dist: pyside6>=6.8.0
12
+ Requires-Dist: pyvista>=0.47.1
13
+ Requires-Dist: pyvistaqt>=0.11.3
14
+ Requires-Dist: vtk>=9.6.1
15
+ Requires-Dist: gmsh>=4.15.0
16
+ Requires-Dist: tabulate>=0.9.0
17
+ Requires-Dist: imageio>=2.37.3
18
+ Requires-Dist: bspmap>=1.0.3
19
+ Requires-Dist: torchfea>=1.1.0
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.12
24
+
25
+ # MorphOpt — A Differentiable Optimization Framework for Soft Structure & Morphology Design
26
+
27
+ **Developed by Zenan Song**
28
+
29
+ A differentiable structural optimization framework that eliminates manual sensitivity derivation by fusing the adjoint method with automatic differentiation (AD). The sensitivity corresponds to the virtual work of residual force derivatives on the adjoint displacement field, computed via a single backpropagation through the residual graph. MorphOpt provides a unified interface for geometry, load, and material definition, calls torchfea for GPU-accelerated differentiable nonlinear FEA and adjoint-AD sensitivity, and employs a trust-region optimizer with L-BFGS for design updates. Validated on SIMP topology optimization with B-spline density fields and pneumatic soft robot shape optimization with deformation-dependent follower loads.
30
+
31
+ ## Features
32
+
33
+ - Custom model definition covering geometry, material, and load parameters
34
+ - Differentiable FEA via torchfea with automatic solving and sensitivity propagation
35
+ - L-BFGS and trust-region methods for parameter updates within a subproblem framework
36
+ - Fully extensible via inheritance — users customize every component in their definition scripts
37
+
38
+ ## Quick Start
39
+
40
+ Install the package:
41
+
42
+ ```bash
43
+ pip install morphopt
44
+ ```
45
+
46
+ Requirements: Python ≥ 3.12; a PyTorch **float64** build is recommended.
47
+
48
+ > **Optimizations are run as scripts.** Each job is an ordinary Python file that calls `morphopt.start_optimization(...)`. It runs headlessly in a terminal (local or remote), and a finished run can be stopped and resumed later from its result folder. Script execution is the recommended way to run jobs.
49
+
50
+ 1. **Run a minimal example** — execute it directly in a terminal:
51
+
52
+ ```bash
53
+ # Shape optimization (pneumatic bending actuator)
54
+ python examples/bendingactuator.py
55
+
56
+ # SIMP topology optimization (compliant gripper)
57
+ python examples/gripper.py
58
+ ```
59
+
60
+ 2. **Run your own job** — copy an example as a starting point, adapt the definition (geometry, material, load, updater, objective), and launch it as a script:
61
+
62
+ ```bash
63
+ python my_task.py
64
+ ```
65
+
66
+ Each run writes its results (logs, FEA files, restart script) into a timestamped result folder under the run root.
67
+
68
+ 3. **Optional — the GUI** is a visual aid for authoring a problem definition and inspecting finished runs in one window. It can also export a runnable script (`.py`), which you can either run directly in the UI or further customize before executing it via Step 2 in a terminal.
69
+
70
+ ```bash
71
+ morphopt-ui # console command, available after `pip install morphopt`
72
+ # python -m morphopt.ui works too (handy when running from a source code directory)
73
+ ```
74
+
75
+ The complete UI workflow (definition part + observer part) is described in [`docs/UI_usage.md`](docs/UI_usage.md).
76
+
77
+ Further references:
78
+
79
+ - Task definition guide: `docs/module_definition_guide.md`
80
+ - Module API reference: `docs/module_reference.md`
81
+ - Theory & papers: `docs/theory/`
82
+
83
+ ## Directory Overview
84
+
85
+ - `src/morphopt/`
86
+ - `optcore` — Core package (controller, params, solver, objective, updaters)
87
+ - `shapeopt/` — B-spline shape optimization
88
+ - `simp/` — SIMP topology optimization
89
+ - `codesign/` — Shell co-design (shape + material)
90
+ - `ui/` — PySide6 graphical UI (definition + observer in one window)
91
+ - `examples/` — Example tasks (bending actuator, gripper, etc.)
92
+ - `docs/` — Usage guides, API reference, theory papers
93
+ - `tests/` — Gradient checks, geometry tests, UI tests
94
+ - `ui_runs/` — runs launched from the UI and their results (`<label>_T<timestamp>/`)
95
+
96
+ ## License
97
+
98
+ Research use preferred. For production or commercial use, please evaluate and ensure numerical and engineering robustness first.
99
+
100
+ ## Citation
101
+
102
+ If you use MorphOpt in your research, please cite:
103
+
104
+ - TRO 2023
105
+
106
+ ```
107
+ @ARTICLE{10296178,
108
+ author={Chen, Feifei and Song, Zenan and Chen, Shitong and Gu, Guoying and Zhu, Xiangyang},
109
+ journal={IEEE Transactions on Robotics},
110
+ title={Morphological Design for Pneumatic Soft Actuators and Robots With Desired Deformation Behavior},
111
+ year={2023},
112
+ volume={39},
113
+ number={6},
114
+ pages={4408-4428},
115
+ keywords={Shape;Surface morphology;Robots;Splines (mathematics);Pneumatic systems;Actuators;Soft robotics;Morphological design;shape optimization;pneumatic soft robots},
116
+ doi={10.1109/TRO.2023.3323825}}
117
+ ```
118
+
119
+ - TRO 2026
120
+
121
+ ```
122
+ @ARTICLE{11617347,
123
+ author={Song, Zenan and Chen, Feifei and Gu, Guoying and Zhu, Xiangyang},
124
+ journal={IEEE Transactions on Robotics},
125
+ title={Continuum Jacobian-Based Computational Morphogenesis for Soft Robotic Workspace Optimization},
126
+ year={2026},
127
+ volume={42},
128
+ number={},
129
+ pages={3048-3068},
130
+ keywords={Optimization;Design methodology;Surfaces;Modeling;End effectors;Shape;Soft robotics;Deformation;Vectors;Robots;Computational morphogenesis;Jacobian shape derivative;soft robotics;workspace optimization},
131
+ doi={10.1109/TRO.2026.3716051}}
132
+
133
+ ```
134
+
135
+ - TMECH 2026
136
+
137
+ ```
138
+ @ARTICLE{11536090,
139
+ author={Song, Zenan and Zhou, Guozhen and Chen, Feifei},
140
+ journal={IEEE/ASME Transactions on Mechatronics},
141
+ title={Contact-Aware Soft Robot Design via Differentiable Simulation and Morphological Optimization},
142
+ year={2026},
143
+ volume={31},
144
+ number={4},
145
+ pages={4576-4584},
146
+ keywords={Contacts;Optimization;Modeling;Design methodology;Soft robotics;Surfaces;Actuators;Materials;Force;Simulation;Differentiable contact modeling;morphological design;soft robotics},
147
+ doi={10.1109/TMECH.2026.3692920}}
148
+
149
+ ```
150
+
151
+
@@ -0,0 +1,127 @@
1
+ # MorphOpt — A Differentiable Optimization Framework for Soft Structure & Morphology Design
2
+
3
+ **Developed by Zenan Song**
4
+
5
+ A differentiable structural optimization framework that eliminates manual sensitivity derivation by fusing the adjoint method with automatic differentiation (AD). The sensitivity corresponds to the virtual work of residual force derivatives on the adjoint displacement field, computed via a single backpropagation through the residual graph. MorphOpt provides a unified interface for geometry, load, and material definition, calls torchfea for GPU-accelerated differentiable nonlinear FEA and adjoint-AD sensitivity, and employs a trust-region optimizer with L-BFGS for design updates. Validated on SIMP topology optimization with B-spline density fields and pneumatic soft robot shape optimization with deformation-dependent follower loads.
6
+
7
+ ## Features
8
+
9
+ - Custom model definition covering geometry, material, and load parameters
10
+ - Differentiable FEA via torchfea with automatic solving and sensitivity propagation
11
+ - L-BFGS and trust-region methods for parameter updates within a subproblem framework
12
+ - Fully extensible via inheritance — users customize every component in their definition scripts
13
+
14
+ ## Quick Start
15
+
16
+ Install the package:
17
+
18
+ ```bash
19
+ pip install morphopt
20
+ ```
21
+
22
+ Requirements: Python ≥ 3.12; a PyTorch **float64** build is recommended.
23
+
24
+ > **Optimizations are run as scripts.** Each job is an ordinary Python file that calls `morphopt.start_optimization(...)`. It runs headlessly in a terminal (local or remote), and a finished run can be stopped and resumed later from its result folder. Script execution is the recommended way to run jobs.
25
+
26
+ 1. **Run a minimal example** — execute it directly in a terminal:
27
+
28
+ ```bash
29
+ # Shape optimization (pneumatic bending actuator)
30
+ python examples/bendingactuator.py
31
+
32
+ # SIMP topology optimization (compliant gripper)
33
+ python examples/gripper.py
34
+ ```
35
+
36
+ 2. **Run your own job** — copy an example as a starting point, adapt the definition (geometry, material, load, updater, objective), and launch it as a script:
37
+
38
+ ```bash
39
+ python my_task.py
40
+ ```
41
+
42
+ Each run writes its results (logs, FEA files, restart script) into a timestamped result folder under the run root.
43
+
44
+ 3. **Optional — the GUI** is a visual aid for authoring a problem definition and inspecting finished runs in one window. It can also export a runnable script (`.py`), which you can either run directly in the UI or further customize before executing it via Step 2 in a terminal.
45
+
46
+ ```bash
47
+ morphopt-ui # console command, available after `pip install morphopt`
48
+ # python -m morphopt.ui works too (handy when running from a source code directory)
49
+ ```
50
+
51
+ The complete UI workflow (definition part + observer part) is described in [`docs/UI_usage.md`](docs/UI_usage.md).
52
+
53
+ Further references:
54
+
55
+ - Task definition guide: `docs/module_definition_guide.md`
56
+ - Module API reference: `docs/module_reference.md`
57
+ - Theory & papers: `docs/theory/`
58
+
59
+ ## Directory Overview
60
+
61
+ - `src/morphopt/`
62
+ - `optcore` — Core package (controller, params, solver, objective, updaters)
63
+ - `shapeopt/` — B-spline shape optimization
64
+ - `simp/` — SIMP topology optimization
65
+ - `codesign/` — Shell co-design (shape + material)
66
+ - `ui/` — PySide6 graphical UI (definition + observer in one window)
67
+ - `examples/` — Example tasks (bending actuator, gripper, etc.)
68
+ - `docs/` — Usage guides, API reference, theory papers
69
+ - `tests/` — Gradient checks, geometry tests, UI tests
70
+ - `ui_runs/` — runs launched from the UI and their results (`<label>_T<timestamp>/`)
71
+
72
+ ## License
73
+
74
+ Research use preferred. For production or commercial use, please evaluate and ensure numerical and engineering robustness first.
75
+
76
+ ## Citation
77
+
78
+ If you use MorphOpt in your research, please cite:
79
+
80
+ - TRO 2023
81
+
82
+ ```
83
+ @ARTICLE{10296178,
84
+ author={Chen, Feifei and Song, Zenan and Chen, Shitong and Gu, Guoying and Zhu, Xiangyang},
85
+ journal={IEEE Transactions on Robotics},
86
+ title={Morphological Design for Pneumatic Soft Actuators and Robots With Desired Deformation Behavior},
87
+ year={2023},
88
+ volume={39},
89
+ number={6},
90
+ pages={4408-4428},
91
+ keywords={Shape;Surface morphology;Robots;Splines (mathematics);Pneumatic systems;Actuators;Soft robotics;Morphological design;shape optimization;pneumatic soft robots},
92
+ doi={10.1109/TRO.2023.3323825}}
93
+ ```
94
+
95
+ - TRO 2026
96
+
97
+ ```
98
+ @ARTICLE{11617347,
99
+ author={Song, Zenan and Chen, Feifei and Gu, Guoying and Zhu, Xiangyang},
100
+ journal={IEEE Transactions on Robotics},
101
+ title={Continuum Jacobian-Based Computational Morphogenesis for Soft Robotic Workspace Optimization},
102
+ year={2026},
103
+ volume={42},
104
+ number={},
105
+ pages={3048-3068},
106
+ keywords={Optimization;Design methodology;Surfaces;Modeling;End effectors;Shape;Soft robotics;Deformation;Vectors;Robots;Computational morphogenesis;Jacobian shape derivative;soft robotics;workspace optimization},
107
+ doi={10.1109/TRO.2026.3716051}}
108
+
109
+ ```
110
+
111
+ - TMECH 2026
112
+
113
+ ```
114
+ @ARTICLE{11536090,
115
+ author={Song, Zenan and Zhou, Guozhen and Chen, Feifei},
116
+ journal={IEEE/ASME Transactions on Mechatronics},
117
+ title={Contact-Aware Soft Robot Design via Differentiable Simulation and Morphological Optimization},
118
+ year={2026},
119
+ volume={31},
120
+ number={4},
121
+ pages={4576-4584},
122
+ keywords={Contacts;Optimization;Modeling;Design methodology;Soft robotics;Surfaces;Actuators;Materials;Force;Simulation;Differentiable contact modeling;morphological design;soft robotics},
123
+ doi={10.1109/TMECH.2026.3692920}}
124
+
125
+ ```
126
+
127
+
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "morphopt"
3
- version = "3.1.5"
3
+ version = "3.2.0"
4
4
  description = "A morphing optimization framework using PyTorch and Abaqus."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -9,7 +9,7 @@ dependencies = [
9
9
  "torchvision>=0.15.1",
10
10
  "numpy>=2.0.0",
11
11
  "pypardiso>=0.4.7",
12
- "pyqt6>=6.11.0",
12
+ "pyside6>=6.8.0",
13
13
  "pyvista>=0.47.1",
14
14
  "pyvistaqt>=0.11.3",
15
15
  "vtk>=9.6.1",
@@ -17,9 +17,13 @@ dependencies = [
17
17
  "tabulate>=0.9.0",
18
18
  "imageio>=2.37.3",
19
19
  "bspmap>=1.0.3",
20
- "torchfea>=1.0.17",
20
+ "torchfea>=1.1.0",
21
21
  "trimesh>=4.11.5",
22
22
  "networkx>=3.6.1",
23
23
  "scipy>=1.17.1",
24
24
  "cpgeo>=1.0.12",
25
25
  ]
26
+
27
+ [project.scripts]
28
+ # console entry for the graphical UI (after `pip install morphopt`)
29
+ morphopt-ui = "morphopt.ui:run_app"
File without changes
@@ -66,7 +66,7 @@ from .optcore.history import History
66
66
  from .optcore.baseobject import BaseObject
67
67
  # endregion
68
68
 
69
- from .opt_runner import start_optimization, debug_optimization, view_optimization_result
69
+ from .opt_runner import start_optimization, debug_optimization
70
70
 
71
71
  # region modules
72
72
  from . import shapeopt
@@ -40,7 +40,7 @@ class CodesignFEAParams(FEAParams):
40
40
  )
41
41
  surfcenter = surfnodes.mean(dim=1)
42
42
 
43
- fe.assembly.get_instance('final_model').external_surface = 'surface_1_offset'
43
+ fe.assembly.get_instance('final_model').exterior_surface = 'surface_1_offset'
44
44
 
45
45
  mesh_1all = fe.assembly.get_instance('final_model').get_mesh(surf_name='surface_1_All')
46
46
  mesh_1offset = fe.assembly.get_instance('final_model').get_mesh(surf_name='surface_1_offset')
@@ -72,4 +72,4 @@ class CodesignFEAParams(FEAParams):
72
72
 
73
73
  raise ValueError("The Gaussian weights of the C3D6 elements are negative. Please check the mesh quality.")
74
74
 
75
- return fe
75
+ return fe
@@ -0,0 +1,82 @@
1
+ """Run / debug optimization workers.
2
+
3
+ Runs started from *code* never open a UI: the PySide6 observer lives inside the
4
+ MorphOpt UI and simply polls the result folder on disk (per finished
5
+ iteration). The old ``no_gui`` flag and separate observer process were
6
+ therefore removed; browse results from the observer page in the main UI.
7
+ """
8
+
9
+
10
+ def start_optimization(device='cpu', restart_per_iteration: int = 20,
11
+ path_result: str = None, target_iteration=None, **kwargs):
12
+ """
13
+ Start an optimization process (always headless).
14
+
15
+ Args:
16
+ device (str, optional): device to use for computation ('cpu'/'cuda:0').
17
+ restart_per_iteration (int): iterations between process restarts.
18
+ path_result (str, optional): existing result folder -> continue there,
19
+ otherwise a fresh timestamped run folder is created.
20
+ target_iteration (int, optional): when continuing, resume from this
21
+ step; None/0 -> resume from the last saved step.
22
+ """
23
+ import multiprocessing as mp
24
+
25
+ mp.set_start_method("spawn", force=True)
26
+
27
+ if path_result is None:
28
+ import __main__
29
+ main_filepath = __main__.__file__
30
+ else:
31
+ main_filepath = path_result + '/scripts/' + 'MAIN_SCRIPT_FOR_RESTART.py'
32
+
33
+ from .taskoptmization import TaskOptimization
34
+
35
+ process_optimization = mp.Process(
36
+ target=TaskOptimization.task_optimization,
37
+ kwargs={'path_result': path_result,
38
+ 'main_filepath': main_filepath,
39
+ 'device': device,
40
+ 'target_iteration': target_iteration,
41
+ 'restart_per_iteration': restart_per_iteration})
42
+ process_optimization.start()
43
+ process_optimization.join()
44
+
45
+
46
+ def debug_optimization(device='cpu', restart_per_iteration: int = 20,
47
+ path_result: str = None, target_iteration=None, **kwargs):
48
+ """
49
+ Run the optimization in the current process (debugger friendly).
50
+ """
51
+ import os
52
+ import sys
53
+ import __main__
54
+ import multiprocessing as mp
55
+
56
+ from .taskoptmization import TaskOptimization
57
+ import morphopt
58
+
59
+ mp.set_start_method("spawn", force=True)
60
+
61
+ if path_result is None:
62
+ main_filepath = __main__.__file__
63
+ else:
64
+ main_filepath = path_result + '/scripts/' + 'MAIN_SCRIPT_FOR_RESTART.py'
65
+
66
+ filename = os.path.splitext(os.path.basename(main_filepath))[0]
67
+ filepath = os.path.dirname(main_filepath)
68
+ os.chdir(filepath)
69
+ sys.path.append(os.getcwd())
70
+
71
+ Controller = getattr(__import__(filename), 'ThisController')
72
+
73
+ controller: morphopt.Controller = Controller()
74
+ controller.restart_per_iteration = restart_per_iteration
75
+ controller.optdevice = device
76
+ controller._debug_mode = True
77
+
78
+ TaskOptimization.optmain(device=device,
79
+ path_result=path_result,
80
+ target_iteration=target_iteration,
81
+ restart_per_iteration=restart_per_iteration,
82
+ main_filepath=main_filepath)
@@ -85,6 +85,8 @@ class FixedGeometryINP(FixedGeometry):
85
85
 
86
86
  assembly = torchfea.Assembly()
87
87
 
88
- assembly.add_part(part=fe_ext.assembly.get_part(self._part_name), name='final_model')
89
- assembly.add_instance(instance=torchfea.Instance(part_name='final_model', external_surface='surface_0_All'), name='final_model')
90
- return assembly
88
+ assembly.add_part(part=fe_ext.assembly.get_part(self._part_name), name='final_model')
89
+ instance = torchfea.Instance(part_name='final_model')
90
+ assembly.add_instance(instance=instance, name='final_model')
91
+ instance.exterior_surface = 'surface_0_All'
92
+ return assembly
@@ -14,7 +14,7 @@ class BaseInterface():
14
14
  Class to handle the surface of the morphable model.
15
15
  """
16
16
 
17
- def __init__(self, symmetric: list[int] = None, *args, **kwargs) -> None:
17
+ def __init__(self, *args, **kwargs) -> None:
18
18
  """
19
19
  Initialize the Surface class.
20
20
 
@@ -23,22 +23,6 @@ class BaseInterface():
23
23
  surf_type (int) : The type of the surface.
24
24
  - 0: bspline surface
25
25
  - 1: closed surface
26
- symmetric (list[int]) : The symmetry of the surface.
27
- - 0: no symmetry
28
- - 1: axis symmetry
29
- 0: x-axis symmetry
30
- 1: y-axis symmetry
31
- 2: z-axis symmetry
32
- """
33
-
34
- self.symmetric: list[int] = symmetric
35
- """
36
- the symmetry of the surface.
37
- # 0: no symmetry
38
- # 1: axis symmetry
39
- ## 0: x-axis symmetry
40
- ## 1: y-axis symmetry
41
- ## 2: z-axis symmetry
42
26
  """
43
27
 
44
28
  self.surf_node_idx: np.ndarray
@@ -737,12 +721,6 @@ class CpBasedInterface(BaseInterface):
737
721
  surf_type (int) : The type of the surface.
738
722
  - 0: bspline surface
739
723
  - 1: closed surface
740
- symmetric (list[int]) : The symmetry of the surface.
741
- - 0: no symmetry
742
- - 1: axis symmetry
743
- 0: x-axis symmetry
744
- 1: y-axis symmetry
745
- 2: z-axis symmetry
746
724
  """
747
725
 
748
726
  super().__init__(*args, **kwargs)
@@ -36,7 +36,7 @@ class BspInterface(CpBasedInterface):
36
36
 
37
37
  def build(self):
38
38
  """
39
- 构建版本 - 改用 addBSplineSurface + Symmetric Wrapping + Trim
39
+ 构建版本 - 改用 addBSplineSurface + Wrapping + Trim
40
40
  通过上下游双重延伸(Padding)确保接缝处C2连续性
41
41
  """
42
42
  self.volume_tag = None
@@ -392,8 +392,8 @@ class BspInterface(CpBasedInterface):
392
392
  gmsh.fltk.run()
393
393
 
394
394
 
395
- def __init__(self, surface: bspmap.BSP, init_size: float, symmetric = [0], MaxR = 0.2, MaxFF = 0.1, MaxC = 1.0):
396
- super().__init__(surface, symmetric)
395
+ def __init__(self, surface: bspmap.BSP, init_size: float, MaxR = 0.2, MaxFF = 0.1, MaxC = 1.0):
396
+ super().__init__(surface)
397
397
 
398
398
  self.model = surface
399
399
  """The B-spline surface model."""
@@ -691,7 +691,7 @@ class BspInterface(CpBasedInterface):
691
691
 
692
692
 
693
693
  @classmethod
694
- def initialize_cylinder(cls, r0: float, length: float, seed_size: float, flip: bool, num_U_ratio: int = 1, num_V_ratio: int = 1, symmetric: list[int] = [0], degree = 3, init_location = [0.,0.,0.], maxR = 0.2, maxC = 1., maxFF = 0.2, perturbation_L = -1.):
694
+ def initialize_cylinder(cls, r0: float, length: float, seed_size: float, flip: bool, num_U_ratio: int = 1, num_V_ratio: int = 1, degree = 3, init_location = [0.,0.,0.], maxR = 0.2, maxC = 1., maxFF = 0.2, perturbation_L = -1.):
695
695
  """
696
696
  Initialize the B-spline surface for the optimization process.
697
697
 
@@ -701,7 +701,6 @@ class BspInterface(CpBasedInterface):
701
701
  seed_size (float): The size of the seed for the B-spline surface.
702
702
  num_U_ratio (int, optional): The ratio for the number of points in the U direction. Default is 1.
703
703
  num_V_ratio (int, optional): The ratio for the number of points in the V direction. Default is 1.
704
- symmetric (list[int]): The symmetry of the surface.
705
704
  flip (bool): Whether to flip the surface or not.
706
705
  degree (int, optional): The degree of the B-spline surface. Default is 3.
707
706
  init_location (list[float], optional): The initial location of the surface. Default is [0., 0., 0.].
@@ -713,7 +712,6 @@ class BspInterface(CpBasedInterface):
713
712
  Returns:
714
713
  BSP (BSP_Surf): The initialized B-spline surface object.
715
714
  surf_type (int): The type of the surface (0 for B-spline surface).
716
- symmetric (list[int]): The symmetry of the surface.
717
715
  """
718
716
 
719
717
  numU = round(r0 * 2 * np.pi / seed_size)
@@ -732,9 +730,6 @@ class BspInterface(CpBasedInterface):
732
730
  [y, x] = torch.meshgrid(y, x, indexing='ij')
733
731
  theta = 2 * torch.pi * x + (1 / numU) * torch.pi
734
732
 
735
- if not flip:
736
- theta = -theta
737
-
738
733
  P0[:, :, 0] = torch.cos(theta) * r0
739
734
  P0[:, :, 1] = torch.sin(theta) * r0
740
735
  P0[:, :, 2] = length * y
@@ -760,7 +755,7 @@ class BspInterface(CpBasedInterface):
760
755
  size=[numV, numU],
761
756
  control_points=P0.cpu().numpy().reshape([-1, 3]))
762
757
 
763
- output = cls(bsp, init_size=seed_size, symmetric=symmetric, MaxR=maxR, MaxC=maxC, MaxFF=maxFF)
758
+ output = cls(bsp, init_size=seed_size, MaxR=maxR, MaxC=maxC, MaxFF=maxFF)
764
759
  output.flip = flip
765
760
 
766
761
  return output
@@ -20,8 +20,8 @@ class CPGEOInterface(CpBasedInterface):
20
20
  providing a flexible alternative to B-spline surfaces for complex geometries.
21
21
  """
22
22
 
23
- def __init__(self, surface: cpgeo.CPGEO, init_size: float, symmetric = [0], MaxC = 1.0):
24
- super().__init__(surface, symmetric)
23
+ def __init__(self, surface: cpgeo.CPGEO, init_size: float, MaxC = 1.0):
24
+ super().__init__(surface)
25
25
 
26
26
  self.model = surface
27
27
  """The CPGEO surface model."""
@@ -363,7 +363,7 @@ class CPGEOInterface(CpBasedInterface):
363
363
 
364
364
  @classmethod
365
365
  def initialize_cylinder(cls, r0: float, length: float, seed_size: float, flip: bool,
366
- num_U_ratio: int = 1, num_V_ratio: int = 1, symmetric: list[int] = [0],
366
+ num_U_ratio: int = 1, num_V_ratio: int = 1,
367
367
  degree = 3, init_location = [0.,0.,0.], maxR = 0.2, maxC = 1., maxFF = 0.2,
368
368
  perturbation_L = -1.):
369
369
  """
@@ -376,7 +376,6 @@ class CPGEOInterface(CpBasedInterface):
376
376
  flip (bool): Whether to flip the surface normal or not.
377
377
  num_U_ratio (int, optional): The ratio for mesh density in circumferential direction. Default is 1.
378
378
  num_V_ratio (int, optional): The ratio for mesh density in axial direction. Default is 1.
379
- symmetric (list[int]): The symmetry of the surface.
380
379
  degree (int, optional): Unused for CPGEO. Default is 3.
381
380
  init_location (list[float], optional): The initial location of the surface. Default is [0., 0., 0.].
382
381
  maxR (float, optional): The maximum curvature derivative constraint. Default is 0.2.
@@ -451,14 +450,14 @@ class CPGEOInterface(CpBasedInterface):
451
450
  )
452
451
 
453
452
  # Create interface
454
- output = cls(cpgeo_model, init_size=seed_size, symmetric=symmetric,
453
+ output = cls(cpgeo_model, init_size=seed_size,
455
454
  MaxR=maxR, MaxC=maxC, MaxFF=maxFF)
456
455
  output.flip = flip
457
456
 
458
457
  return output
459
458
 
460
459
  @classmethod
461
- def initialize_Sphere(cls, r0: float, seed_size: float, flip: bool, symmetric: list[int] = [0], init_location = [0.,0.,0.],
460
+ def initialize_Sphere(cls, r0: float, seed_size: float, flip: bool, init_location = [0.,0.,0.],
462
461
  MaxC = 1.0):
463
462
  """
464
463
  Initialize the CPGEO surface for sphere shape optimization.
@@ -467,7 +466,6 @@ class CPGEOInterface(CpBasedInterface):
467
466
  r0 (float): The radius of the sphere.
468
467
  seed_size (float): The size of the mesh seed.
469
468
  flip (bool): Whether to flip the surface normal or not.
470
- symmetric (list[int]): The symmetry of the surface.
471
469
  init_location (list[float], optional): The initial location of the surface. Default is [0., 0., 0.].
472
470
  MaxC (float, optional): The maximum curvature constraint. Default is 1.0
473
471
  Returns:
@@ -505,7 +503,7 @@ class CPGEOInterface(CpBasedInterface):
505
503
  )
506
504
 
507
505
  # Create interface
508
- output = cls(cpgeo_model, init_size=seed_size, symmetric=symmetric, MaxC=MaxC)
506
+ output = cls(cpgeo_model, init_size=seed_size, MaxC=MaxC)
509
507
  output.flip = flip
510
508
 
511
509
  return output
@@ -581,7 +581,7 @@ class GeometryParams(BaseGeometry):
581
581
 
582
582
  def apply_surface_constraints(self) -> None:
583
583
  """
584
- Apply the constraints (e.g. the symmetric constraint) of the surfaces.
584
+ Apply the constraints (e.g. the surface constraint) of the surfaces.
585
585
  """
586
586
  pass
587
587
 
@@ -640,7 +640,9 @@ class GeometryParams(BaseGeometry):
640
640
  assembly = torchfea.Assembly()
641
641
 
642
642
  assembly.add_part(part=part, name='final_model')
643
- assembly.add_instance(instance=torchfea.Instance(part_name='final_model', external_surface='surface_0_All'), name='final_model')
643
+ instance = torchfea.Instance(part_name='final_model')
644
+ assembly.add_instance(instance=instance, name='final_model')
645
+ instance.exterior_surface = 'surface_0_All'
644
646
  return assembly
645
647
 
646
648
  def _regenerate(self, path_result: str, pools = None):
@@ -776,4 +778,3 @@ class GeometryParams(BaseGeometry):
776
778
  nodes_new[part.mid_pt_idxmap_torch[:, 2]] = (nodes_new[part.mid_pt_idxmap_torch[:, 0]] + nodes_new[part.mid_pt_idxmap_torch[:, 1]]) / 2
777
779
 
778
780
  part.nodes = nodes_new
779
-