morphopt 3.2.2__tar.gz → 4.0.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 (247) hide show
  1. {morphopt-3.2.2/src/morphopt.egg-info → morphopt-4.0.1}/PKG-INFO +12 -4
  2. morphopt-3.2.2/PKG-INFO → morphopt-4.0.1/README.md +7 -25
  3. {morphopt-3.2.2 → morphopt-4.0.1}/pyproject.toml +23 -3
  4. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/__init__.py +52 -29
  5. morphopt-4.0.1/src/morphopt/codesign/__init__.py +16 -0
  6. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/codesign/constraints.py +169 -70
  7. morphopt-4.0.1/src/morphopt/codesign/offset_boundary_part.py +263 -0
  8. morphopt-4.0.1/src/morphopt/codesign/update_offset_boundary_part.py +29 -0
  9. morphopt-4.0.1/src/morphopt/constants.py +1275 -0
  10. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/opt_runner.py +36 -19
  11. morphopt-4.0.1/src/morphopt/optcore/__init__.py +24 -0
  12. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/optcore/controller.py +183 -121
  13. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/optcore/history.py +174 -141
  14. morphopt-4.0.1/src/morphopt/optcore/modelparams/__init__.py +33 -0
  15. morphopt-4.0.1/src/morphopt/optcore/modelparams/base_model_component.py +16 -0
  16. morphopt-4.0.1/src/morphopt/optcore/modelparams/baseparam.py +170 -0
  17. morphopt-4.0.1/src/morphopt/optcore/modelparams/fea/__init__.py +10 -0
  18. morphopt-3.2.2/src/morphopt/optcore/modelparams/feainterface/basefeainterface.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/fea/base_component.py +19 -6
  19. morphopt-3.2.2/src/morphopt/optcore/modelparams/feainterface/bodyforceinterface.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/fea/body_force.py +27 -17
  20. morphopt-3.2.2/src/morphopt/optcore/modelparams/feainterface/boundaryconditioninterface.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/fea/boundary_condition.py +24 -7
  21. morphopt-3.2.2/src/morphopt/optcore/modelparams/feainterface/contactinterface.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/fea/contact.py +18 -14
  22. morphopt-3.2.2/src/morphopt/optcore/modelparams/feainterface/coupleinterface.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/fea/couple.py +8 -4
  23. morphopt-3.2.2/src/morphopt/optcore/modelparams/feainterface/pointinterface.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/fea/point_load.py +3 -3
  24. morphopt-3.2.2/src/morphopt/optcore/modelparams/feainterface/pressureinterface.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/fea/pressure.py +10 -6
  25. morphopt-3.2.2/src/morphopt/optcore/modelparams/feainterface/referencepointinterface.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/fea/reference_point.py +4 -4
  26. morphopt-3.2.2/src/morphopt/optcore/modelparams/feainterface/springinterface.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/fea/spring.py +4 -4
  27. morphopt-4.0.1/src/morphopt/optcore/modelparams/feaparams.py +137 -0
  28. morphopt-4.0.1/src/morphopt/optcore/modelparams/geometry.py +66 -0
  29. morphopt-4.0.1/src/morphopt/optcore/modelparams/materials/__init__.py +11 -0
  30. morphopt-3.2.2/src/morphopt/optcore/modelparams/materialinterface/basematerialinterface.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/materials/base_material.py +39 -16
  31. morphopt-3.2.2/src/morphopt/optcore/modelparams/materialinterface/homogeneousmaterial.py → morphopt-4.0.1/src/morphopt/optcore/modelparams/materials/homogeneous_material.py +3 -3
  32. morphopt-4.0.1/src/morphopt/optcore/modelparams/materialsparams.py +25 -0
  33. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/optcore/modelparams/params.py +69 -51
  34. morphopt-4.0.1/src/morphopt/optcore/modelparams/parts/__init__.py +21 -0
  35. morphopt-4.0.1/src/morphopt/optcore/modelparams/parts/base_part.py +212 -0
  36. morphopt-4.0.1/src/morphopt/optcore/modelparams/parts/box_part.py +146 -0
  37. morphopt-4.0.1/src/morphopt/optcore/modelparams/parts/cad_part.py +128 -0
  38. morphopt-4.0.1/src/morphopt/optcore/modelparams/parts/inp_part.py +72 -0
  39. morphopt-4.0.1/src/morphopt/optcore/modelparams/parts/torch_fea_part.py +177 -0
  40. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/optcore/objfunc.py +29 -19
  41. morphopt-4.0.1/src/morphopt/optcore/protocal.py +130 -0
  42. morphopt-4.0.1/src/morphopt/optcore/quadrature.py +78 -0
  43. morphopt-4.0.1/src/morphopt/optcore/solver.py +239 -0
  44. morphopt-4.0.1/src/morphopt/optcore/updaters.py +781 -0
  45. morphopt-4.0.1/src/morphopt/postprocess/__init__.py +9 -0
  46. morphopt-4.0.1/src/morphopt/postprocess/exporters.py +117 -0
  47. morphopt-4.0.1/src/morphopt/postprocess/fields.py +321 -0
  48. morphopt-4.0.1/src/morphopt/shapeopt/__init__.py +25 -0
  49. morphopt-4.0.1/src/morphopt/shapeopt/boundary_part.py +532 -0
  50. morphopt-4.0.1/src/morphopt/shapeopt/meshgenerator.py +312 -0
  51. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/shapeopt/objectivefuncs/boundarys.py +17 -9
  52. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/shapeopt/objectivefuncs/distancesurface.py +27 -10
  53. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/shapeopt/objectivefuncs/shapederivative.py +88 -63
  54. morphopt-4.0.1/src/morphopt/shapeopt/objectivefuncs/surfacefairness.py +66 -0
  55. morphopt-4.0.1/src/morphopt/shapeopt/objectivefuncs/volumemaximization.py +61 -0
  56. morphopt-4.0.1/src/morphopt/shapeopt/surfaces/__init__.py +28 -0
  57. morphopt-4.0.1/src/morphopt/shapeopt/surfaces/base_constraints.py +116 -0
  58. morphopt-3.2.2/src/morphopt/shapeopt/geometryinterfaces/basesurfaceinterface.py → morphopt-4.0.1/src/morphopt/shapeopt/surfaces/base_surface.py +118 -77
  59. morphopt-4.0.1/src/morphopt/shapeopt/surfaces/bsp_constraints.py +91 -0
  60. morphopt-3.2.2/src/morphopt/shapeopt/geometryinterfaces/bspsurfaceinterface.py → morphopt-4.0.1/src/morphopt/shapeopt/surfaces/bsp_surface.py +126 -109
  61. morphopt-4.0.1/src/morphopt/shapeopt/surfaces/cpgeo_constraints.py +211 -0
  62. morphopt-3.2.2/src/morphopt/shapeopt/geometryinterfaces/cpgeosurfaceinterface.py → morphopt-4.0.1/src/morphopt/shapeopt/surfaces/cpgeo_surface.py +79 -70
  63. morphopt-4.0.1/src/morphopt/shapeopt/update_boundary_part.py +460 -0
  64. morphopt-4.0.1/src/morphopt/simp/__init__.py +10 -0
  65. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/simp/objectivefuncs/boundarys.py +17 -12
  66. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/simp/objectivefuncs/densityfield.py +5 -1
  67. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/simp/objectivefuncs/volfrac.py +13 -17
  68. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/simp/simpmaterial.py +492 -263
  69. morphopt-4.0.1/src/morphopt/simp/update_simpmaterial.py +410 -0
  70. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/taskoptmization.py +44 -17
  71. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/ui/__init__.py +10 -5
  72. morphopt-4.0.1/src/morphopt/ui/app.py +51 -0
  73. morphopt-4.0.1/src/morphopt/ui/application/__init__.py +42 -0
  74. morphopt-4.0.1/src/morphopt/ui/application/cad.py +85 -0
  75. morphopt-3.2.2/src/morphopt/ui/widgets/code_completion.py → morphopt-4.0.1/src/morphopt/ui/application/completion.py +22 -34
  76. morphopt-4.0.1/src/morphopt/ui/application/definitions.py +212 -0
  77. morphopt-4.0.1/src/morphopt/ui/application/devices.py +14 -0
  78. morphopt-4.0.1/src/morphopt/ui/application/edit_history.py +202 -0
  79. morphopt-4.0.1/src/morphopt/ui/application/editing.py +401 -0
  80. morphopt-4.0.1/src/morphopt/ui/application/editor_routing.py +116 -0
  81. morphopt-4.0.1/src/morphopt/ui/application/expressions.py +43 -0
  82. morphopt-4.0.1/src/morphopt/ui/application/fields.py +116 -0
  83. morphopt-4.0.1/src/morphopt/ui/application/finite_element.py +193 -0
  84. morphopt-4.0.1/src/morphopt/ui/application/imported_models.py +79 -0
  85. morphopt-4.0.1/src/morphopt/ui/application/part_sets.py +117 -0
  86. morphopt-4.0.1/src/morphopt/ui/application/quickstart.py +741 -0
  87. morphopt-4.0.1/src/morphopt/ui/application/results.py +161 -0
  88. morphopt-4.0.1/src/morphopt/ui/application/runs.py +283 -0
  89. morphopt-4.0.1/src/morphopt/ui/application/updaters.py +187 -0
  90. {morphopt-3.2.2/src/morphopt/ui/widgets → morphopt-4.0.1/src/morphopt/ui/application}/values.py +35 -38
  91. morphopt-4.0.1/src/morphopt/ui/codegen/custom_classes.py +433 -0
  92. morphopt-4.0.1/src/morphopt/ui/codegen/generator.py +1203 -0
  93. morphopt-4.0.1/src/morphopt/ui/fea_worker.py +53 -0
  94. morphopt-4.0.1/src/morphopt/ui/i18n.py +136 -0
  95. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/ui/launcher.py +6 -4
  96. morphopt-4.0.1/src/morphopt/ui/locales/en-US.json +1207 -0
  97. morphopt-4.0.1/src/morphopt/ui/locales/zh-CN.json +1207 -0
  98. morphopt-4.0.1/src/morphopt/ui/mainwindow.py +444 -0
  99. morphopt-4.0.1/src/morphopt/ui/model/__init__.py +38 -0
  100. morphopt-4.0.1/src/morphopt/ui/model/base_nodes.py +690 -0
  101. morphopt-4.0.1/src/morphopt/ui/model/chamberlayout.py +164 -0
  102. morphopt-4.0.1/src/morphopt/ui/model/configuration.py +101 -0
  103. morphopt-4.0.1/src/morphopt/ui/model/fields.py +38 -0
  104. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/ui/model/loaders.py +3 -4
  105. morphopt-4.0.1/src/morphopt/ui/model/material_models.py +15 -0
  106. morphopt-4.0.1/src/morphopt/ui/model/modelinfo.py +119 -0
  107. morphopt-4.0.1/src/morphopt/ui/model/node_types/__init__.py +170 -0
  108. morphopt-4.0.1/src/morphopt/ui/model/node_types/cad.py +665 -0
  109. morphopt-4.0.1/src/morphopt/ui/model/node_types/custom_code.py +116 -0
  110. morphopt-4.0.1/src/morphopt/ui/model/node_types/loads.py +426 -0
  111. morphopt-4.0.1/src/morphopt/ui/model/node_types/materials.py +347 -0
  112. morphopt-4.0.1/src/morphopt/ui/model/node_types/objectives.py +68 -0
  113. morphopt-4.0.1/src/morphopt/ui/model/node_types/parts.py +445 -0
  114. morphopt-4.0.1/src/morphopt/ui/model/node_types/penalties.py +321 -0
  115. morphopt-4.0.1/src/morphopt/ui/model/node_types/structural.py +612 -0
  116. morphopt-4.0.1/src/morphopt/ui/model/node_types/surfaces.py +267 -0
  117. morphopt-4.0.1/src/morphopt/ui/model/node_types/symmetry.py +172 -0
  118. morphopt-4.0.1/src/morphopt/ui/model/problem.py +1759 -0
  119. morphopt-4.0.1/src/morphopt/ui/model/registry.py +282 -0
  120. morphopt-4.0.1/src/morphopt/ui/observe_panel.py +558 -0
  121. morphopt-4.0.1/src/morphopt/ui/presentation/__init__.py +1 -0
  122. morphopt-4.0.1/src/morphopt/ui/presentation/edit_history.py +12 -0
  123. morphopt-4.0.1/src/morphopt/ui/presentation/history.py +83 -0
  124. morphopt-4.0.1/src/morphopt/ui/presentation/labels.py +327 -0
  125. morphopt-4.0.1/src/morphopt/ui/presentation/navigation.py +337 -0
  126. morphopt-4.0.1/src/morphopt/ui/refresh.py +109 -0
  127. morphopt-4.0.1/src/morphopt/ui/schemes/__init__.py +26 -0
  128. morphopt-4.0.1/src/morphopt/ui/schemes/base.py +391 -0
  129. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/ui/schemes/snippets.py +27 -42
  130. morphopt-4.0.1/src/morphopt/ui/theme/__init__.py +56 -0
  131. morphopt-4.0.1/src/morphopt/ui/theme/manager.py +135 -0
  132. morphopt-4.0.1/src/morphopt/ui/theme/palette.py +385 -0
  133. morphopt-4.0.1/src/morphopt/ui/theme/styles/__init__.py +9 -0
  134. morphopt-4.0.1/src/morphopt/ui/theme/styles/base.qss +26 -0
  135. morphopt-4.0.1/src/morphopt/ui/theme/styles/controls.qss +88 -0
  136. morphopt-4.0.1/src/morphopt/ui/theme/styles/inputs.qss +23 -0
  137. morphopt-4.0.1/src/morphopt/ui/theme/stylesheet.py +34 -0
  138. morphopt-4.0.1/src/morphopt/ui/theme/themes/__init__.py +11 -0
  139. morphopt-4.0.1/src/morphopt/ui/theme/themes/dark.py +86 -0
  140. morphopt-4.0.1/src/morphopt/ui/theme/themes/light.py +114 -0
  141. morphopt-4.0.1/src/morphopt/ui/visualization/__init__.py +42 -0
  142. morphopt-4.0.1/src/morphopt/ui/visualization/geometry.py +1057 -0
  143. morphopt-4.0.1/src/morphopt/ui/visualization/loads.py +554 -0
  144. morphopt-4.0.1/src/morphopt/ui/visualization/scene.py +145 -0
  145. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/ui/widgets/codeeditor.py +58 -35
  146. morphopt-4.0.1/src/morphopt/ui/widgets/collection_controls.py +102 -0
  147. morphopt-4.0.1/src/morphopt/ui/widgets/controller_editor.py +137 -0
  148. morphopt-4.0.1/src/morphopt/ui/widgets/custom_classes.py +469 -0
  149. morphopt-4.0.1/src/morphopt/ui/widgets/definition_actions.py +569 -0
  150. morphopt-4.0.1/src/morphopt/ui/widgets/definition_manager.py +569 -0
  151. morphopt-4.0.1/src/morphopt/ui/widgets/edit_history.py +359 -0
  152. morphopt-4.0.1/src/morphopt/ui/widgets/editor.py +252 -0
  153. morphopt-4.0.1/src/morphopt/ui/widgets/editor_pages.py +57 -0
  154. morphopt-4.0.1/src/morphopt/ui/widgets/file_dialogs.py +158 -0
  155. morphopt-4.0.1/src/morphopt/ui/widgets/finite_element.py +493 -0
  156. morphopt-4.0.1/src/morphopt/ui/widgets/helper_editor.py +140 -0
  157. morphopt-4.0.1/src/morphopt/ui/widgets/language_selector.py +43 -0
  158. morphopt-4.0.1/src/morphopt/ui/widgets/model_tree.py +550 -0
  159. morphopt-4.0.1/src/morphopt/ui/widgets/objective_editor.py +879 -0
  160. morphopt-4.0.1/src/morphopt/ui/widgets/observation_pages.py +359 -0
  161. morphopt-4.0.1/src/morphopt/ui/widgets/param_form.py +228 -0
  162. morphopt-4.0.1/src/morphopt/ui/widgets/plot_style.py +28 -0
  163. morphopt-4.0.1/src/morphopt/ui/widgets/preview_renderer.py +628 -0
  164. morphopt-4.0.1/src/morphopt/ui/widgets/quickstart.py +971 -0
  165. morphopt-4.0.1/src/morphopt/ui/widgets/run_dialogs.py +125 -0
  166. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/ui/widgets/solver_editor.py +51 -66
  167. morphopt-4.0.1/src/morphopt/ui/widgets/source_view.py +23 -0
  168. morphopt-4.0.1/src/morphopt/ui/widgets/stepmatrix.py +191 -0
  169. morphopt-4.0.1/src/morphopt/ui/widgets/template_insert_dialog.py +122 -0
  170. morphopt-4.0.1/src/morphopt/ui/widgets/theme_selector.py +46 -0
  171. morphopt-4.0.1/src/morphopt/ui/widgets/torchfea_model_editor.py +406 -0
  172. morphopt-4.0.1/src/morphopt/ui/widgets/updater_editor.py +786 -0
  173. morphopt-4.0.1/src/morphopt/ui/widgets/values.py +33 -0
  174. morphopt-4.0.1/src/morphopt/ui/widgets/viewer.py +283 -0
  175. morphopt-4.0.1/src/morphopt/ui/workbench.py +909 -0
  176. morphopt-3.2.2/README.md → morphopt-4.0.1/src/morphopt.egg-info/PKG-INFO +33 -1
  177. morphopt-4.0.1/src/morphopt.egg-info/SOURCES.txt +192 -0
  178. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt.egg-info/requires.txt +4 -1
  179. morphopt-3.2.2/src/morphopt/codesign/__init__.py +0 -20
  180. morphopt-3.2.2/src/morphopt/codesign/feaparams.py +0 -80
  181. morphopt-3.2.2/src/morphopt/codesign/geometry.py +0 -362
  182. morphopt-3.2.2/src/morphopt/codesign/params.py +0 -4
  183. morphopt-3.2.2/src/morphopt/optcore/__init__.py +0 -8
  184. morphopt-3.2.2/src/morphopt/optcore/baseobject.py +0 -48
  185. morphopt-3.2.2/src/morphopt/optcore/modelparams/__init__.py +0 -5
  186. morphopt-3.2.2/src/morphopt/optcore/modelparams/baseparam.py +0 -133
  187. morphopt-3.2.2/src/morphopt/optcore/modelparams/feainterface/__init__.py +0 -10
  188. morphopt-3.2.2/src/morphopt/optcore/modelparams/feaparams.py +0 -239
  189. morphopt-3.2.2/src/morphopt/optcore/modelparams/geometry.py +0 -251
  190. morphopt-3.2.2/src/morphopt/optcore/modelparams/materialinterface/__init__.py +0 -11
  191. morphopt-3.2.2/src/morphopt/optcore/modelparams/materials.py +0 -175
  192. morphopt-3.2.2/src/morphopt/optcore/solver.py +0 -179
  193. morphopt-3.2.2/src/morphopt/optcore/updaters.py +0 -384
  194. morphopt-3.2.2/src/morphopt/shapeopt/__init__.py +0 -10
  195. morphopt-3.2.2/src/morphopt/shapeopt/geometryinterfaces/__init__.py +0 -3
  196. morphopt-3.2.2/src/morphopt/shapeopt/geometryparams.py +0 -794
  197. morphopt-3.2.2/src/morphopt/shapeopt/objectivefuncs/surfacefairness.py +0 -38
  198. morphopt-3.2.2/src/morphopt/shapeopt/objectivefuncs/volumemaximization.py +0 -25
  199. morphopt-3.2.2/src/morphopt/shapeopt/objfunc.py +0 -13
  200. morphopt-3.2.2/src/morphopt/shapeopt/update_geometry.py +0 -335
  201. morphopt-3.2.2/src/morphopt/simp/__init__.py +0 -12
  202. morphopt-3.2.2/src/morphopt/simp/solver.py +0 -41
  203. morphopt-3.2.2/src/morphopt/simp/update_material.py +0 -324
  204. morphopt-3.2.2/src/morphopt/ui/app.py +0 -64
  205. morphopt-3.2.2/src/morphopt/ui/codegen/generator.py +0 -586
  206. morphopt-3.2.2/src/morphopt/ui/i18n.py +0 -74
  207. morphopt-3.2.2/src/morphopt/ui/mainwindow.py +0 -209
  208. morphopt-3.2.2/src/morphopt/ui/model/__init__.py +0 -20
  209. morphopt-3.2.2/src/morphopt/ui/model/problem.py +0 -1220
  210. morphopt-3.2.2/src/morphopt/ui/model/schemas.py +0 -847
  211. morphopt-3.2.2/src/morphopt/ui/observe_panel.py +0 -968
  212. morphopt-3.2.2/src/morphopt/ui/schemes/__init__.py +0 -18
  213. morphopt-3.2.2/src/morphopt/ui/schemes/base.py +0 -206
  214. morphopt-3.2.2/src/morphopt/ui/schemes/codesign.py +0 -155
  215. morphopt-3.2.2/src/morphopt/ui/schemes/shapeopt.py +0 -104
  216. morphopt-3.2.2/src/morphopt/ui/schemes/simp.py +0 -112
  217. morphopt-3.2.2/src/morphopt/ui/widgets/editor.py +0 -370
  218. morphopt-3.2.2/src/morphopt/ui/widgets/model_tree.py +0 -565
  219. morphopt-3.2.2/src/morphopt/ui/widgets/objective_editor.py +0 -233
  220. morphopt-3.2.2/src/morphopt/ui/widgets/observation_pages.py +0 -246
  221. morphopt-3.2.2/src/morphopt/ui/widgets/param_form.py +0 -159
  222. morphopt-3.2.2/src/morphopt/ui/widgets/stepmatrix.py +0 -226
  223. morphopt-3.2.2/src/morphopt/ui/widgets/template_insert_dialog.py +0 -198
  224. morphopt-3.2.2/src/morphopt/ui/widgets/torchfea_model_editor.py +0 -428
  225. morphopt-3.2.2/src/morphopt/ui/widgets/updater_editor.py +0 -699
  226. morphopt-3.2.2/src/morphopt/ui/widgets/viewer.py +0 -352
  227. morphopt-3.2.2/src/morphopt/ui/workbench.py +0 -553
  228. morphopt-3.2.2/src/morphopt.egg-info/SOURCES.txt +0 -109
  229. morphopt-3.2.2/tests/test_fixedGeometry.py +0 -24
  230. morphopt-3.2.2/tests/test_path.py +0 -12
  231. morphopt-3.2.2/tests/test_ui.py +0 -62
  232. {morphopt-3.2.2 → morphopt-4.0.1}/setup.cfg +0 -0
  233. /morphopt-3.2.2/src/morphopt/optcore/modelparams/materialinterface/materialmodels.py → /morphopt-4.0.1/src/morphopt/optcore/modelparams/materials/models.py +0 -0
  234. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/shapeopt/objectivefuncs/__init__.py +0 -0
  235. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/shapeopt/objectivefuncs/basefuncs.py +0 -0
  236. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/simp/objectivefuncs/__init__.py +0 -0
  237. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/simp/objectivefuncs/basefuncs.py +0 -0
  238. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/simp/objectivefuncs/sensitivity.py +0 -0
  239. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/ui/__main__.py +0 -0
  240. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/ui/codegen/__init__.py +0 -0
  241. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/ui/widgets/__init__.py +0 -0
  242. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/utils/__init__.py +0 -0
  243. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/utils/gradient_check.py +0 -0
  244. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt/utils/history_read.py +0 -0
  245. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt.egg-info/dependency_links.txt +0 -0
  246. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt.egg-info/entry_points.txt +0 -0
  247. {morphopt-3.2.2 → morphopt-4.0.1}/src/morphopt.egg-info/top_level.txt +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: morphopt
3
- Version: 3.2.2
4
- Summary: A morphing optimization framework using PyTorch and Abaqus.
3
+ Version: 4.0.1
4
+ Summary: A morphing optimization framework using PyTorch and torchfea.
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
7
7
  Requires-Dist: torch>=2.9.1
@@ -16,11 +16,13 @@ Requires-Dist: gmsh>=4.15.0
16
16
  Requires-Dist: tabulate>=0.9.0
17
17
  Requires-Dist: imageio>=2.37.3
18
18
  Requires-Dist: bspmap>=1.0.3
19
- Requires-Dist: torchfea>=1.1.1
19
+ Requires-Dist: torchfea>=1.1.2
20
20
  Requires-Dist: trimesh>=4.11.5
21
21
  Requires-Dist: networkx>=3.6.1
22
22
  Requires-Dist: scipy>=1.17.1
23
23
  Requires-Dist: cpgeo>=1.0.12
24
+ Provides-Extra: test
25
+ Requires-Dist: pytest>=8.0; extra == "test"
24
26
 
25
27
  # MorphOpt — A Differentiable Optimization Framework for Soft Structure & Morphology Design
26
28
 
@@ -72,7 +74,13 @@ Requirements: Python ≥ 3.12; a PyTorch **float64** build is recommended.
72
74
  # python -m morphopt.ui works too (handy when running from a source code directory)
73
75
  ```
74
76
 
75
- The complete UI workflow (definition part + observer part) is described in [`docs/UI_usage.md`](docs/UI_usage.md).
77
+ The GUI opens directly into the full definition workbench with its standard sections present and no problem setup prefilled. Build a definition yourself or use **Quickstart** to choose shape or topology optimization, define geometry separately, and add weighted objective terms with their own load conditions. Workspace terms select their driving pressure channels and use boundary integration. Generated problems stay editable and can be saved or exported as runnable scripts.
78
+
79
+ The complete UI workflow (definition part + observer part) is described in [`docs/UIguide.md`](docs/UIguide.md).
80
+
81
+ ### Numeric configuration
82
+
83
+ Shared UI defaults and tunable kernel parameters live in [`src/morphopt/constants.py`](src/morphopt/constants.py), grouped under `CONSTANT.UI` and `CONSTANT.KERNEL`. Code accesses them directly, for example `CONSTANT.UI.VIEWER.RENDER.LABEL_FONT_SIZE` or `CONSTANT.KERNEL.SOLVER.NUM_PROCESS`. Edit a value there to change its default; restart MorphOpt for the change to take effect. Coordinate indices, tensor dimensions, and coefficients that define mathematical formulas remain in code. UI translations remain in JSON files under `src/morphopt/ui/locales/`.
76
84
 
77
85
  Further references:
78
86
 
@@ -1,27 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: morphopt
3
- Version: 3.2.2
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.1
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
1
  # MorphOpt — A Differentiable Optimization Framework for Soft Structure & Morphology Design
26
2
 
27
3
  **Developed by Zenan Song**
@@ -72,7 +48,13 @@ Requirements: Python ≥ 3.12; a PyTorch **float64** build is recommended.
72
48
  # python -m morphopt.ui works too (handy when running from a source code directory)
73
49
  ```
74
50
 
75
- The complete UI workflow (definition part + observer part) is described in [`docs/UI_usage.md`](docs/UI_usage.md).
51
+ The GUI opens directly into the full definition workbench with its standard sections present and no problem setup prefilled. Build a definition yourself or use **Quickstart** to choose shape or topology optimization, define geometry separately, and add weighted objective terms with their own load conditions. Workspace terms select their driving pressure channels and use boundary integration. Generated problems stay editable and can be saved or exported as runnable scripts.
52
+
53
+ The complete UI workflow (definition part + observer part) is described in [`docs/UIguide.md`](docs/UIguide.md).
54
+
55
+ ### Numeric configuration
56
+
57
+ Shared UI defaults and tunable kernel parameters live in [`src/morphopt/constants.py`](src/morphopt/constants.py), grouped under `CONSTANT.UI` and `CONSTANT.KERNEL`. Code accesses them directly, for example `CONSTANT.UI.VIEWER.RENDER.LABEL_FONT_SIZE` or `CONSTANT.KERNEL.SOLVER.NUM_PROCESS`. Edit a value there to change its default; restart MorphOpt for the change to take effect. Coordinate indices, tensor dimensions, and coefficients that define mathematical formulas remain in code. UI translations remain in JSON files under `src/morphopt/ui/locales/`.
76
58
 
77
59
  Further references:
78
60
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "morphopt"
3
- version = "3.2.2"
4
- description = "A morphing optimization framework using PyTorch and Abaqus."
3
+ version = "4.0.1"
4
+ description = "A morphing optimization framework using PyTorch and torchfea."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
7
7
  dependencies = [
@@ -17,7 +17,7 @@ dependencies = [
17
17
  "tabulate>=0.9.0",
18
18
  "imageio>=2.37.3",
19
19
  "bspmap>=1.0.3",
20
- "torchfea>=1.1.1",
20
+ "torchfea>=1.1.2",
21
21
  "trimesh>=4.11.5",
22
22
  "networkx>=3.6.1",
23
23
  "scipy>=1.17.1",
@@ -27,3 +27,23 @@ dependencies = [
27
27
  [project.scripts]
28
28
  # console entry for the graphical UI (after `pip install morphopt`)
29
29
  morphopt-ui = "morphopt.ui:run_app"
30
+
31
+ [project.optional-dependencies]
32
+ # Install with: python -m pip install -e ".[test]"
33
+ test = [
34
+ "pytest>=8.0",
35
+ ]
36
+
37
+ [tool.pytest.ini_options]
38
+ testpaths = ["tests"]
39
+ pythonpath = ["src"]
40
+ addopts = "-ra"
41
+
42
+ [tool.ruff.lint]
43
+ extend-select = ["RUF022"]
44
+
45
+ [tool.setuptools.package-data]
46
+ "morphopt.ui" = [
47
+ "locales/*.json",
48
+ "theme/styles/*.qss",
49
+ ]
@@ -13,6 +13,7 @@ if __sys.platform.startswith("linux"):
13
13
  # region: Logging Configuration
14
14
  import logging as __logging
15
15
 
16
+
16
17
  def enable_logging(level=__logging.INFO, log_file=None, file_log_level=__logging.DEBUG):
17
18
  """
18
19
  Enable logging for the FEA package.
@@ -25,7 +26,7 @@ def enable_logging(level=__logging.INFO, log_file=None, file_log_level=__logging
25
26
  the path to a log file where logs will be written. If None, logs will only be printed to the console.
26
27
  file_log_level : int
27
28
  the logging level for the log file. Default is logging.INFO.
28
-
29
+
29
30
  Examples
30
31
  --------
31
32
  >>> import torchfea
@@ -33,59 +34,81 @@ def enable_logging(level=__logging.INFO, log_file=None, file_log_level=__logging
33
34
  """
34
35
  logger = __logging.getLogger(__name__)
35
36
  logger.setLevel(min(level, file_log_level))
36
-
37
+
37
38
  # clear existing handlers to avoid duplicate logs
38
39
  logger.handlers.clear()
39
-
40
+
40
41
  # logging to console
41
42
  console = __logging.StreamHandler()
42
43
  console.setLevel(level)
43
- console.setFormatter(__logging.Formatter(
44
- '%(asctime)s | %(levelname)-7s | %(message)s',
45
- datefmt='%Y-%m-%d %H:%M:%S'
46
- ))
44
+ console.setFormatter(
45
+ __logging.Formatter(
46
+ "%(asctime)s | %(levelname)-7s | %(message)s", datefmt="%Y-%m-%d %H:%M:%S"
47
+ )
48
+ )
47
49
  logger.addHandler(console)
48
-
50
+
49
51
  # logging to file if log_file is provided
50
52
  if log_file:
51
- file_handler = __logging.FileHandler(log_file, encoding='utf-8')
53
+ file_handler = __logging.FileHandler(log_file, encoding="utf-8")
52
54
  file_handler.setLevel(file_log_level)
53
- file_handler.setFormatter(__logging.Formatter(
54
- '%(asctime)s | %(levelname)-7s | %(name)s | %(message)s'
55
- ))
55
+ file_handler.setFormatter(
56
+ __logging.Formatter(
57
+ "%(asctime)s | %(levelname)-7s | %(name)s | %(message)s"
58
+ )
59
+ )
56
60
  logger.addHandler(file_handler)
57
61
 
58
62
  return logger
59
- # endregion
60
-
61
63
 
62
64
 
65
+ # endregion
63
66
 
64
67
 
65
- # region optcore imports
68
+ # region modules (loaded after the core classes they subclass)
69
+ from . import codesign, shapeopt, simp
70
+ from .opt_runner import debug_optimization, start_optimization
66
71
  from .optcore.controller import Controller
72
+ from .optcore.history import History
67
73
  from .optcore.modelparams import (
68
- FEAParams, FixedGeometryINP, FixedGeometryTorchFEA, FixedGeometry,
69
- MaterialsParams, Params,
74
+ BaseModelComponent,
75
+ BasePart,
76
+ CADPart,
77
+ BoxPart,
78
+ FEAParams,
79
+ GeometryParams,
80
+ INPPart,
81
+ MaterialsParams,
82
+ Params,
83
+ TorchFEAPart,
84
+ load_model_assembly,
85
+ resolve_model_path,
86
+ )
87
+ from .optcore.modelparams.materials import HomogeneousMaterial
88
+ from .optcore.objfunc import ObjectiveFunction
89
+ from .optcore.protocal import (
90
+ ProtocalInitializable,
91
+ ProtocalSavable,
92
+ ProtocalUpdatable,
93
+ ProtocalVisualizable,
70
94
  )
71
95
  from .optcore.solver import Solver
72
- from .optcore.modelparams import Params
73
96
  from .optcore.updaters import Updaters
74
- from .optcore.objfunc import ObjectiveFunction
75
- from .optcore.history import History
76
- from .optcore.baseobject import BaseObject
77
- # endregion
78
-
79
- from .opt_runner import start_optimization, debug_optimization
97
+ from .shapeopt import (
98
+ BoundaryPart,
99
+ UpdaterBoundaryPart,
100
+ BaseSurfaceConstraints,
101
+ SurfaceRelationConstraint,
102
+ BspSurfaceRelationConstraint,
103
+ CPGEOSurfaceRelationConstraint,
104
+ )
105
+ from .codesign import OffsetBoundaryPart, UpdaterOffsetBoundaryPart
106
+ from .simp import SIMP_BSPFieldMaterials, UpdaterSIMPMaterial
80
107
 
81
- # region modules
82
- from . import shapeopt
83
- from . import codesign
84
- from . import simp
85
108
  # endregion
86
-
87
109
  # region scripts
88
110
  from .utils import check_gradients, get_controller
111
+
89
112
  # endregion
90
113
 
91
114
  controller: Controller = None
@@ -0,0 +1,16 @@
1
+ """Cavity offset Parts and their geometry updater.
2
+
3
+ Compose parameters, objectives, solvers and updater collections using the
4
+ common morphopt interfaces. SIMP materials use the simp interfaces.
5
+ """
6
+
7
+ from .offset_boundary_part import OffsetBoundaryPart
8
+ from .update_offset_boundary_part import UpdaterOffsetBoundaryPart
9
+ from .constraints import InwardCurvatureRadius, OffsetSurfaceMinThickness
10
+
11
+ __all__ = [
12
+ "OffsetBoundaryPart",
13
+ "UpdaterOffsetBoundaryPart",
14
+ "InwardCurvatureRadius",
15
+ "OffsetSurfaceMinThickness",
16
+ ]
@@ -1,7 +1,8 @@
1
1
  import torch
2
2
 
3
+ from ..constants import CONSTANT
3
4
  from ..shapeopt.objectivefuncs.basefuncs import BaseConstraints
4
- from .geometry import CodesignGeometry
5
+ from .offset_boundary_part import OffsetBoundaryPart
5
6
 
6
7
 
7
8
  class InwardCurvatureRadius(BaseConstraints):
@@ -15,23 +16,21 @@ class InwardCurvatureRadius(BaseConstraints):
15
16
 
16
17
  def __init__(
17
18
  self,
18
- geometry: CodesignGeometry,
19
19
  surface_start: int = 1,
20
20
  surface_ids: list[int] | None = None,
21
- margin: float = 0.4,
22
- margin_ratio: float = 0.45,
23
- barrier_thre_ratio: float = 0.1,
24
- barrier_ratio: float = 0.0,
25
- p: int = 8,
26
- penalty_scale: float = 1e3,
27
- hard_violation_beta: float = 8.0,
21
+ margin: float = CONSTANT.KERNEL.CODESIGN.CURVATURE_MARGIN,
22
+ margin_ratio: float = CONSTANT.KERNEL.CODESIGN.CURVATURE_MARGIN_RATIO,
23
+ barrier_thre_ratio: float = CONSTANT.KERNEL.CODESIGN.CURVATURE_BARRIER_THRESHOLD_RATIO,
24
+ barrier_ratio: float = CONSTANT.KERNEL.CODESIGN.BARRIER_PENALTY_RATIO,
25
+ p: int = CONSTANT.KERNEL.CODESIGN.BARRIER_EXPONENT,
26
+ penalty_scale: float = CONSTANT.KERNEL.CODESIGN.PENALTY_SCALE,
27
+ hard_violation_beta: float = CONSTANT.KERNEL.CODESIGN.HARD_VIOLATION_BETA,
28
28
  normal_sign: float = 1.0,
29
29
  ) -> None:
30
30
  """
31
31
  Initialize the inward curvature radius constraint.
32
32
 
33
33
  Args:
34
- geometry (CodesignGeometry): The geometry parameters containing the surfaces.
35
34
  surface_start (int, optional): The starting index of surfaces to apply the constraint. Defaults to 1.
36
35
  surface_ids (list[int] | None, optional): The specific surface indices to apply the constraint. If None, applies to all surfaces starting from surface_start. Defaults to None.
37
36
  margin (float, optional): The absolute margin added to thickness for curvature limit. Defaults to 0.4.
@@ -42,17 +41,16 @@ class InwardCurvatureRadius(BaseConstraints):
42
41
  penalty_scale (float, optional): Global multiplier for this constraint penalty. Defaults to 1e3.
43
42
  hard_violation_beta (float, optional): Exponential amplification factor for large violations. Defaults to 8.0.
44
43
  normal_sign (float, optional): The sign to determine inward direction. Use 1.0 if normals point outward, -1.0 if normals point inward. Defaults to 1.0.
45
-
46
- """
47
44
 
45
+ """
48
46
 
49
47
  super().__init__()
50
48
 
51
- self.geometry = geometry
52
- """Stores the geometry used by InwardCurvatureRadius."""
53
49
  self.surface_start = int(surface_start)
54
50
  """Stores the surface start used by InwardCurvatureRadius."""
55
- self.surface_ids = None if surface_ids is None else [int(i) for i in surface_ids]
51
+ self.surface_ids = (
52
+ None if surface_ids is None else [int(i) for i in surface_ids]
53
+ )
56
54
  """Stores the surface ids used by InwardCurvatureRadius."""
57
55
 
58
56
  self.margin = margin
@@ -73,7 +71,11 @@ class InwardCurvatureRadius(BaseConstraints):
73
71
  """Stores the normal sign used by InwardCurvatureRadius."""
74
72
 
75
73
  @staticmethod
76
- def _principal_curvatures(rdu: torch.Tensor, rdu2: torch.Tensor, eps: float = 1e-12) -> tuple[torch.Tensor, torch.Tensor]:
74
+ def _principal_curvatures(
75
+ rdu: torch.Tensor,
76
+ rdu2: torch.Tensor,
77
+ eps: float = CONSTANT.KERNEL.CODESIGN.GEOMETRY_TOLERANCE,
78
+ ) -> tuple[torch.Tensor, torch.Tensor]:
77
79
  normal0 = torch.cross(rdu[:, :, 1], rdu[:, :, 0], dim=1)
78
80
  normal = normal0 / (normal0.norm(dim=1, keepdim=True) + eps)
79
81
 
@@ -93,26 +95,51 @@ class InwardCurvatureRadius(BaseConstraints):
93
95
  k2 = 0.5 * (tr - root)
94
96
  return k1, k2
95
97
 
98
+ def initialize(self, r0, rdu0, *args, part_interface=None, **kwargs) -> None:
99
+ """Take the Part this constraint is evaluated for.
100
+
101
+ The geometry updater hands over the Part it evaluates; only a
102
+ :class:`~morphopt.codesign.OffsetBoundaryPart` carries a
103
+ shell, so anything else is rejected here.
104
+ """
105
+ super().initialize(r0=r0, rdu0=rdu0, *args, **kwargs)
106
+ if not isinstance(part_interface, OffsetBoundaryPart):
107
+ raise TypeError(
108
+ f"{type(self).__name__} is evaluated for one co-design Part "
109
+ f"(got {type(part_interface).__name__})."
110
+ )
111
+ self.shell_thickness = float(part_interface.shell_thickness)
112
+
96
113
  def _selected_surface_ids(self, n_surface: int) -> list[int]:
97
114
  if self.surface_ids is None:
98
115
  return [i for i in range(max(self.surface_start, 0), n_surface)]
99
116
  return [i for i in self.surface_ids if 0 <= i < n_surface]
100
117
 
101
- def __call__(self, r: list[torch.Tensor], rdu: list[torch.Tensor], rdu2: list[torch.Tensor], *args, **kwargs) -> torch.Tensor:
118
+ def __call__(
119
+ self,
120
+ r: list[torch.Tensor],
121
+ rdu: list[torch.Tensor],
122
+ rdu2: list[torch.Tensor],
123
+ *args,
124
+ **kwargs,
125
+ ) -> torch.Tensor:
102
126
  loss = torch.zeros(1, device=r[0].device, dtype=r[0].dtype)
103
127
 
104
- t = float(self.geometry.shell_thickness)
105
- if t <= 0:
106
- return loss
107
-
108
- margin_abs = (self.margin_ratio * t) + self.margin
109
- margin_abs = max(float(margin_abs), 1e-12)
110
- t_eff = t + margin_abs
128
+ for i in self._selected_surface_ids(len(r)):
129
+ t = self.shell_thickness
130
+ if t <= 0:
131
+ continue
111
132
 
112
- k_limit = 1.0 / t_eff
113
- barrier_thre = max(k_limit * self.barrier_thre_ratio, 1e-12)
133
+ margin_abs = max(
134
+ float((self.margin_ratio * t) + self.margin),
135
+ CONSTANT.KERNEL.CODESIGN.GEOMETRY_TOLERANCE,
136
+ )
137
+ k_limit = 1.0 / (t + margin_abs)
138
+ barrier_thre = max(
139
+ k_limit * self.barrier_thre_ratio,
140
+ CONSTANT.KERNEL.CODESIGN.GEOMETRY_TOLERANCE,
141
+ )
114
142
 
115
- for i in self._selected_surface_ids(len(r)):
116
143
  k1, k2 = self._principal_curvatures(rdu[i], rdu2[i])
117
144
 
118
145
  k1_in = torch.relu(self.normal_sign * k1)
@@ -120,16 +147,24 @@ class InwardCurvatureRadius(BaseConstraints):
120
147
  k_inward = torch.maximum(k1_in, k2_in)
121
148
 
122
149
  violation = k_inward - k_limit
123
- index, penalty = self.barrier_function(violation, barrier_thre, self.barrier_ratio, self.p)
150
+ index, penalty = self.barrier_function(
151
+ violation, barrier_thre, self.barrier_ratio, self.p
152
+ )
124
153
  if index.numel() > 0:
125
154
  # Strong amplification: base polynomial barrier + exponential hard-violation boost.
126
155
  rel_violation = (violation[index] / barrier_thre).clamp(min=0.0)
127
- hard_boost = torch.exp((self.hard_violation_beta * (rel_violation - 1.0)).clamp(min=0.0, max=20.0))
156
+ hard_boost = torch.exp(
157
+ (self.hard_violation_beta * (rel_violation - 1.0)).clamp(
158
+ min=0.0,
159
+ max=CONSTANT.KERNEL.CODESIGN.HARD_VIOLATION_EXPONENT_MAX,
160
+ )
161
+ )
128
162
  penalty_strong = self.penalty_scale * penalty * hard_boost
129
163
  loss = loss + (self.scaler[i][index] * penalty_strong).sum()
130
164
 
131
165
  return loss
132
166
 
167
+
133
168
  class OffsetSurfaceMinThickness(BaseConstraints):
134
169
  """
135
170
  Enforce a minimum distance on the offset surface to reduce self-intersection risk.
@@ -140,28 +175,36 @@ class OffsetSurfaceMinThickness(BaseConstraints):
140
175
 
141
176
  def __init__(
142
177
  self,
143
- geometry: CodesignGeometry,
144
178
  surface_start: int = 1,
145
179
  surface_ids: list[int] | None = None,
146
180
  min_distance: float | None = None,
147
- search_ratio: float = 1.5,
148
- barrier_thre_ratio: float = 0.05,
149
- barrier_ratio: float = 0.0,
150
- p: int = 8,
151
- penalty_scale: float = 1e3,
152
- hard_violation_beta: float = 8.0,
181
+ search_ratio: float = CONSTANT.KERNEL.CODESIGN.THICKNESS_SEARCH_RATIO,
182
+ barrier_thre_ratio: float = CONSTANT.KERNEL.CODESIGN.THICKNESS_BARRIER_THRESHOLD_RATIO,
183
+ barrier_ratio: float = CONSTANT.KERNEL.CODESIGN.BARRIER_PENALTY_RATIO,
184
+ p: int = CONSTANT.KERNEL.CODESIGN.BARRIER_EXPONENT,
185
+ penalty_scale: float = CONSTANT.KERNEL.CODESIGN.PENALTY_SCALE,
186
+ hard_violation_beta: float = CONSTANT.KERNEL.CODESIGN.HARD_VIOLATION_BETA,
153
187
  normal_sign: float = 1.0,
154
- normal_opposition_thre: float = 0.0,
155
- normal_min: float = -0.7,
156
- normal_max: float = -0.5,
188
+ normal_opposition_thre: float = CONSTANT.KERNEL.CODESIGN.NORMAL_OPPOSITION_THRESHOLD,
189
+ normal_min: float = CONSTANT.KERNEL.CODESIGN.NORMAL_TRANSITION_MIN,
190
+ normal_max: float = CONSTANT.KERNEL.CODESIGN.NORMAL_TRANSITION_MAX,
157
191
  ) -> None:
192
+ """
193
+ Initialize the minimum thickness constraint for the offset surface.
194
+
195
+ Args:
196
+ surface_start (int, optional): The starting index of surfaces to apply the constraint. Defaults to 1.
197
+ surface_ids (list[int] | None, optional): The specific surface indices to apply the constraint. If None, applies to all surfaces starting from surface_start. Defaults to None.
198
+ min_distance (float | None, optional): The required minimum distance.
199
+ Defaults to twice the shell thickness.
200
+ """
158
201
  super().__init__()
159
202
 
160
- self.geometry = geometry
161
- """Stores the geometry used by OffsetSurfaceMinThickness."""
162
203
  self.surface_start = int(surface_start)
163
204
  """Stores the surface start used by OffsetSurfaceMinThickness."""
164
- self.surface_ids = None if surface_ids is None else [int(i) for i in surface_ids]
205
+ self.surface_ids = (
206
+ None if surface_ids is None else [int(i) for i in surface_ids]
207
+ )
165
208
  """Stores the surface ids used by OffsetSurfaceMinThickness."""
166
209
 
167
210
  self.min_distance = min_distance
@@ -200,36 +243,66 @@ class OffsetSurfaceMinThickness(BaseConstraints):
200
243
  @staticmethod
201
244
  def _surface_normals(rdu_sf: torch.Tensor) -> torch.Tensor:
202
245
  normal0 = torch.cross(rdu_sf[:, :, 1], rdu_sf[:, :, 0], dim=1)
203
- normals = normal0 / (normal0.norm(dim=1, keepdim=True) + 1e-12)
246
+ normals = normal0 / (
247
+ normal0.norm(dim=1, keepdim=True)
248
+ + CONSTANT.KERNEL.CODESIGN.GEOMETRY_TOLERANCE
249
+ )
204
250
  return normals
205
251
 
206
- def _offset_points(self, r_sf: torch.Tensor, rdu_sf: torch.Tensor) -> tuple[torch.Tensor, torch.Tensor]:
252
+ def _offset_points(
253
+ self, r_sf: torch.Tensor, rdu_sf: torch.Tensor, thickness: float
254
+ ) -> tuple[torch.Tensor, torch.Tensor]:
255
+ """Offset surface points and the normals they were offset along."""
207
256
  normals = self._surface_normals(rdu_sf=rdu_sf)
208
- thickness = float(self.geometry.shell_thickness)
209
257
  return r_sf + self.normal_sign * thickness * normals, normals
210
258
 
211
- def initialize(self, r0, rdu0, *args, **kwargs) -> None:
259
+ def _min_distance(self, thickness: float) -> float:
260
+ dmin = (
261
+ float(self.min_distance)
262
+ if self.min_distance is not None
263
+ else (2.0 * thickness)
264
+ )
265
+ return max(dmin, CONSTANT.KERNEL.CODESIGN.GEOMETRY_TOLERANCE)
266
+
267
+ def initialize(self, r0, rdu0, *args, part_interface=None, **kwargs) -> None:
268
+ """Take the Part this constraint is evaluated for and pair its points.
269
+
270
+ The geometry updater hands over the Part it evaluates; only a
271
+ :class:`~morphopt.codesign.OffsetBoundaryPart` carries a
272
+ shell, so anything else is rejected here.
273
+ """
212
274
  super().initialize(r0=r0, rdu0=rdu0, *args, **kwargs)
275
+ if not isinstance(part_interface, OffsetBoundaryPart):
276
+ raise TypeError(
277
+ f"{type(self).__name__} is evaluated for one co-design Part "
278
+ f"(got {type(part_interface).__name__})."
279
+ )
280
+ self.shell_thickness = float(part_interface.shell_thickness)
213
281
 
214
282
  self._neighbor_pairs = {}
215
283
  self._neighbor_mindist = {}
216
284
 
217
- import scipy.spatial
285
+ if self.shell_thickness <= 0:
286
+ return
218
287
 
219
- thickness = float(self.geometry.shell_thickness)
220
- dmin = float(self.min_distance) if self.min_distance is not None else (2.0 * thickness)
221
- dmin = max(dmin, 1e-12)
222
- search_radius = max(dmin * self.search_ratio, dmin)
288
+ import scipy.spatial
223
289
 
224
290
  for sf_idx in self._selected_surface_ids(len(r0)):
225
- roff, normals = self._offset_points(r_sf=r0[sf_idx], rdu_sf=rdu0[sf_idx])
291
+ dmin = self._min_distance(self.shell_thickness)
292
+ search_radius = max(dmin * self.search_ratio, dmin)
293
+
294
+ roff, normals = self._offset_points(
295
+ r_sf=r0[sf_idx], rdu_sf=rdu0[sf_idx], thickness=self.shell_thickness
296
+ )
226
297
 
227
298
  tree = scipy.spatial.KDTree(roff.detach().cpu().numpy())
228
- pairs_np = tree.query_pairs(r=search_radius, output_type='ndarray')
299
+ pairs_np = tree.query_pairs(r=search_radius, output_type="ndarray")
229
300
  if pairs_np.size == 0:
230
301
  continue
231
302
 
232
- pairs = torch.from_numpy(pairs_np.T).to(dtype=torch.int64, device=r0[sf_idx].device)
303
+ pairs = torch.from_numpy(pairs_np.T).to(
304
+ dtype=torch.int64, device=r0[sf_idx].device
305
+ )
233
306
 
234
307
  dotn = (normals[pairs[0]] * normals[pairs[1]]).sum(dim=1)
235
308
  opposition = (-dotn).clamp(min=0.0)
@@ -239,22 +312,29 @@ class OffsetSurfaceMinThickness(BaseConstraints):
239
312
  self._neighbor_pairs[sf_idx] = pairs
240
313
  self._neighbor_mindist[sf_idx] = dmin * opposition[keep]
241
314
 
242
- def __call__(self, r: list[torch.Tensor], rdu: list[torch.Tensor], rdu2: list[torch.Tensor], *args, **kwargs) -> torch.Tensor:
315
+ def __call__(
316
+ self,
317
+ r: list[torch.Tensor],
318
+ rdu: list[torch.Tensor],
319
+ rdu2: list[torch.Tensor],
320
+ *args,
321
+ **kwargs,
322
+ ) -> torch.Tensor:
243
323
  loss = torch.zeros(1, device=r[0].device, dtype=r[0].dtype)
244
324
 
245
- if float(self.geometry.shell_thickness) <= 0:
246
- return loss
247
-
248
- thickness = float(self.geometry.shell_thickness)
249
- dmin = float(self.min_distance) if self.min_distance is not None else (2.0 * thickness)
250
- dmin = max(dmin, 1e-12)
251
- barrier_thre = max(dmin * self.barrier_thre_ratio, 1e-12)
252
-
253
325
  for sf_idx in self._selected_surface_ids(len(r)):
254
326
  pairs = self._neighbor_pairs.get(sf_idx, None)
255
327
  if pairs is None or pairs.numel() == 0:
256
328
  continue
257
329
 
330
+ thickness = self.shell_thickness
331
+ if thickness <= 0:
332
+ continue
333
+ barrier_thre = max(
334
+ self._min_distance(thickness) * self.barrier_thre_ratio,
335
+ CONSTANT.KERNEL.CODESIGN.GEOMETRY_TOLERANCE,
336
+ )
337
+
258
338
  # Base surface normals (offset surface shares same normal direction)
259
339
  normals = self._surface_normals(rdu_sf=rdu[sf_idx])
260
340
  dotn = (normals[pairs[0]] * normals[pairs[1]]).sum(dim=1)
@@ -267,27 +347,46 @@ class OffsetSurfaceMinThickness(BaseConstraints):
267
347
  pairs_n = pairs[:, mask_n]
268
348
  dotn_n = dotn[mask_n]
269
349
  mindist_n = self._neighbor_mindist[sf_idx][mask_n].to(
270
- device=r[sf_idx].device, dtype=r[sf_idx].dtype)
350
+ device=r[sf_idx].device, dtype=r[sf_idx].dtype
351
+ )
271
352
  scaler_n0 = self.scaler[sf_idx][pairs_n[0]]
272
353
  scaler_n1 = self.scaler[sf_idx][pairs_n[1]]
273
354
 
274
355
  # Offset points and distance
275
- roff, _ = self._offset_points(r_sf=r[sf_idx], rdu_sf=rdu[sf_idx])
356
+ roff, _ = self._offset_points(
357
+ r_sf=r[sf_idx], rdu_sf=rdu[sf_idx], thickness=thickness
358
+ )
276
359
  delta = roff[pairs_n[0]] - roff[pairs_n[1]]
277
- dist = torch.sqrt((delta * delta).sum(dim=1) + 1e-18)
360
+ dist = torch.sqrt(
361
+ (delta * delta).sum(dim=1)
362
+ + CONSTANT.KERNEL.CODESIGN.DISTANCE_SQUARED_TOLERANCE
363
+ )
278
364
 
279
365
  violation = mindist_n - dist + barrier_thre
280
- indexl, l = self.barrier_function(violation, barrier_thre, self.barrier_ratio, self.p)
366
+ indexl, l = self.barrier_function(
367
+ violation, barrier_thre, self.barrier_ratio, self.p
368
+ )
281
369
 
282
370
  if indexl.numel() > 0:
283
371
  # Smooth normal penalty (same as Distance class)
284
- np_val = (self.normal_max - torch.clamp(dotn_n[indexl], self.normal_min, self.normal_max)) / (self.normal_max - self.normal_min)
372
+ np_val = (
373
+ self.normal_max
374
+ - torch.clamp(dotn_n[indexl], self.normal_min, self.normal_max)
375
+ ) / (self.normal_max - self.normal_min)
285
376
  np_smooth = (6 * np_val**2 - 15 * np_val + 10) * np_val**3
286
377
 
287
378
  rel_violation = (violation[indexl] / barrier_thre).clamp(min=0.0)
288
- hard_boost = torch.exp((self.hard_violation_beta * (rel_violation - 1.0)).clamp(min=0.0, max=20.0))
379
+ hard_boost = torch.exp(
380
+ (self.hard_violation_beta * (rel_violation - 1.0)).clamp(
381
+ min=0.0,
382
+ max=CONSTANT.KERNEL.CODESIGN.HARD_VIOLATION_EXPONENT_MAX,
383
+ )
384
+ )
289
385
  penalty_strong = self.penalty_scale * l * hard_boost * np_smooth
290
386
 
291
- loss = loss + (penalty_strong * scaler_n0[indexl] * scaler_n1[indexl]).sum()
387
+ loss = (
388
+ loss
389
+ + (penalty_strong * scaler_n0[indexl] * scaler_n1[indexl]).sum()
390
+ )
292
391
 
293
392
  return loss