morphopt 3.1.5__tar.gz → 3.1.6__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 (107) hide show
  1. {morphopt-3.1.5 → morphopt-3.1.6}/PKG-INFO +22 -9
  2. {morphopt-3.1.5 → morphopt-3.1.6}/README.md +20 -7
  3. {morphopt-3.1.5 → morphopt-3.1.6}/pyproject.toml +6 -2
  4. {morphopt-3.1.5 → morphopt-3.1.6}/setup.cfg +0 -0
  5. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/__init__.py +1 -1
  6. morphopt-3.1.6/src/morphopt/opt_runner.py +82 -0
  7. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/basesurfaceinterface.py +1 -23
  8. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/bspsurfaceinterface.py +5 -10
  9. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/cpgeosurfaceinterface.py +6 -8
  10. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryparams.py +1 -1
  11. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/distancesurface.py +0 -0
  12. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/shapederivative.py +0 -0
  13. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/taskoptmization.py +18 -23
  14. morphopt-3.1.6/src/morphopt/taskui.py +18 -0
  15. morphopt-3.1.6/src/morphopt/ui/__init__.py +37 -0
  16. morphopt-3.1.6/src/morphopt/ui/__main__.py +6 -0
  17. morphopt-3.1.6/src/morphopt/ui/app.py +57 -0
  18. morphopt-3.1.6/src/morphopt/ui/codegen/__init__.py +1 -0
  19. morphopt-3.1.6/src/morphopt/ui/codegen/generator.py +367 -0
  20. morphopt-3.1.6/src/morphopt/ui/codegen/objective_templates.py +52 -0
  21. morphopt-3.1.6/src/morphopt/ui/launcher.py +153 -0
  22. morphopt-3.1.6/src/morphopt/ui/mainwindow.py +146 -0
  23. morphopt-3.1.6/src/morphopt/ui/model/__init__.py +16 -0
  24. morphopt-3.1.6/src/morphopt/ui/model/loaders.py +32 -0
  25. morphopt-3.1.6/src/morphopt/ui/model/problem.py +170 -0
  26. morphopt-3.1.6/src/morphopt/ui/model/schemas.py +489 -0
  27. morphopt-3.1.6/src/morphopt/ui/monitor.py +558 -0
  28. morphopt-3.1.6/src/morphopt/ui/observe_panel.py +533 -0
  29. morphopt-3.1.6/src/morphopt/ui/schemes/__init__.py +14 -0
  30. morphopt-3.1.6/src/morphopt/ui/schemes/base.py +101 -0
  31. morphopt-3.1.6/src/morphopt/ui/schemes/codesign.py +173 -0
  32. morphopt-3.1.6/src/morphopt/ui/schemes/shapeopt.py +127 -0
  33. morphopt-3.1.6/src/morphopt/ui/schemes/simp.py +115 -0
  34. morphopt-3.1.6/src/morphopt/ui/widgets/__init__.py +1 -0
  35. morphopt-3.1.6/src/morphopt/ui/widgets/codeeditor.py +207 -0
  36. morphopt-3.1.6/src/morphopt/ui/widgets/editor.py +305 -0
  37. morphopt-3.1.6/src/morphopt/ui/widgets/model_tree.py +282 -0
  38. morphopt-3.1.6/src/morphopt/ui/widgets/objective_editor.py +141 -0
  39. morphopt-3.1.6/src/morphopt/ui/widgets/param_form.py +152 -0
  40. morphopt-3.1.6/src/morphopt/ui/widgets/solver_editor.py +181 -0
  41. morphopt-3.1.6/src/morphopt/ui/widgets/stepmatrix.py +207 -0
  42. morphopt-3.1.6/src/morphopt/ui/widgets/updater_editor.py +214 -0
  43. morphopt-3.1.6/src/morphopt/ui/widgets/values.py +63 -0
  44. morphopt-3.1.6/src/morphopt/ui/widgets/viewer.py +252 -0
  45. morphopt-3.1.6/src/morphopt/ui/workbench.py +313 -0
  46. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt.egg-info/PKG-INFO +22 -9
  47. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt.egg-info/SOURCES.txt +32 -0
  48. morphopt-3.1.6/src/morphopt.egg-info/entry_points.txt +2 -0
  49. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt.egg-info/requires.txt +1 -1
  50. {morphopt-3.1.5 → morphopt-3.1.6}/tests/test_ui.py +0 -0
  51. morphopt-3.1.5/src/morphopt/opt_runner.py +0 -143
  52. morphopt-3.1.5/src/morphopt/taskui.py +0 -494
  53. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/__init__.py +0 -0
  54. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/constraints.py +0 -0
  55. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/feaparams.py +0 -0
  56. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/geometry.py +0 -0
  57. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/material.py +0 -0
  58. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/params.py +0 -0
  59. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/__init__.py +0 -0
  60. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/baseobject.py +0 -0
  61. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/controller.py +0 -0
  62. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/history.py +0 -0
  63. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/__init__.py +0 -0
  64. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/baseparam.py +0 -0
  65. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/__init__.py +0 -0
  66. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/basefeainterface.py +0 -0
  67. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/bodyforceinterface.py +0 -0
  68. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/boundaryconditioninterface.py +0 -0
  69. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/contactinterface.py +0 -0
  70. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/coupleinterface.py +0 -0
  71. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/pointinterface.py +0 -0
  72. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/pressureinterface.py +0 -0
  73. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/referencepointinterface.py +0 -0
  74. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/springinterface.py +0 -0
  75. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feaparams.py +0 -0
  76. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/geometry.py +0 -0
  77. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/materials.py +0 -0
  78. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/params.py +0 -0
  79. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/objfunc.py +0 -0
  80. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/solver.py +0 -0
  81. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/updaters.py +0 -0
  82. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/__init__.py +0 -0
  83. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/__init__.py +0 -0
  84. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/__init__.py +0 -0
  85. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/basefuncs.py +0 -0
  86. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/boundarys.py +0 -0
  87. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/surfacefairness.py +0 -0
  88. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/volumemaximization.py +0 -0
  89. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objfunc.py +0 -0
  90. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/update_geometry.py +0 -0
  91. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/__init__.py +0 -0
  92. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/__init__.py +0 -0
  93. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/basefuncs.py +0 -0
  94. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/boundarys.py +0 -0
  95. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/densityfield.py +0 -0
  96. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/sensitivity.py +0 -0
  97. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/volfrac.py +0 -0
  98. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/simpmaterial.py +0 -0
  99. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/solver.py +0 -0
  100. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/update_material.py +0 -0
  101. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/utils/__init__.py +0 -0
  102. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/utils/gradient_check.py +0 -0
  103. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/utils/history_read.py +0 -0
  104. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt.egg-info/dependency_links.txt +0 -0
  105. {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt.egg-info/top_level.txt +0 -0
  106. {morphopt-3.1.5 → morphopt-3.1.6}/tests/test_fixedGeometry.py +0 -0
  107. {morphopt-3.1.5 → morphopt-3.1.6}/tests/test_path.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: morphopt
3
- Version: 3.1.5
3
+ Version: 3.1.6
4
4
  Summary: A morphing optimization framework using PyTorch and Abaqus.
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
@@ -8,7 +8,7 @@ Requires-Dist: torch>=2.9.1
8
8
  Requires-Dist: torchvision>=0.15.1
9
9
  Requires-Dist: numpy>=2.0.0
10
10
  Requires-Dist: pypardiso>=0.4.7
11
- Requires-Dist: pyqt6>=6.11.0
11
+ Requires-Dist: pyside6>=6.8.0
12
12
  Requires-Dist: pyvista>=0.47.1
13
13
  Requires-Dist: pyvistaqt>=0.11.3
14
14
  Requires-Dist: vtk>=9.6.1
@@ -22,7 +22,7 @@ Requires-Dist: networkx>=3.6.1
22
22
  Requires-Dist: scipy>=1.17.1
23
23
  Requires-Dist: cpgeo>=1.0.12
24
24
 
25
- # MorphOpt —— A Differentiable Optimization Framework for Soft Structure & Morphology Design
25
+ # MorphOpt — A Differentiable Optimization Framework for Soft Structure & Morphology Design
26
26
 
27
27
  **Developed by Zenan Song**
28
28
 
@@ -45,14 +45,23 @@ pip install morphopt
45
45
  2. Run a minimal example:
46
46
 
47
47
  ```bash
48
- # Shape optimization
49
- python examples/basic/shapeoptimization.py
48
+ # Shape optimization (pneumatic bending actuator)
49
+ python examples/bendingactuator.py
50
50
 
51
- # SIMP topology optimization
52
- python examples/basic/simp.py
51
+ # SIMP topology optimization (compliant gripper)
52
+ python examples/gripper.py
53
53
  ```
54
54
 
55
- 3. More usage examples:
55
+ 3. **Launch the GUI (recommended)** — define, run and observe an optimization all inside one window:
56
+
57
+ ```bash
58
+ morphopt-ui # console command, available after `pip install morphopt`
59
+ # python -m morphopt.ui works too (handy when running from a source code directory)
60
+ ```
61
+
62
+ The complete UI workflow (definition part + observer part) is described in [`docs/UI_usage.md`](docs/UI_usage.md).
63
+
64
+ Further references:
56
65
 
57
66
  - Task definition guide: `docs/module_definition_guide.md`
58
67
  - Module API reference: `docs/module_reference.md`
@@ -64,9 +73,13 @@ python examples/basic/simp.py
64
73
  - `optcore` — Core package (controller, params, solver, objective, updaters)
65
74
  - `shapeopt/` — B-spline shape optimization
66
75
  - `simp/` — SIMP topology optimization
76
+ - `codesign/` — Shell co-design (shape + material)
77
+ - `ui/` — PySide6 graphical UI (definition + observer in one window)
67
78
  - `examples/` — Example tasks (bending actuator, gripper, etc.)
68
- - `docs/` — Usage guides, API reference, and theory papers
79
+ - `docs/` — Usage guides, API reference, theory papers
80
+ - [`UI_usage.md`](docs/UI_usage.md) — graphical UI user guide
69
81
  - `tests/` — Gradient checks, geometry tests, UI tests
82
+ - `ui_runs/` — runs launched from the UI and their results (`<label>_T<timestamp>/`)
70
83
 
71
84
  ## License
72
85
 
@@ -1,4 +1,4 @@
1
- # MorphOpt —— A Differentiable Optimization Framework for Soft Structure & Morphology Design
1
+ # MorphOpt — A Differentiable Optimization Framework for Soft Structure & Morphology Design
2
2
 
3
3
  **Developed by Zenan Song**
4
4
 
@@ -21,14 +21,23 @@ pip install morphopt
21
21
  2. Run a minimal example:
22
22
 
23
23
  ```bash
24
- # Shape optimization
25
- python examples/basic/shapeoptimization.py
24
+ # Shape optimization (pneumatic bending actuator)
25
+ python examples/bendingactuator.py
26
26
 
27
- # SIMP topology optimization
28
- python examples/basic/simp.py
27
+ # SIMP topology optimization (compliant gripper)
28
+ python examples/gripper.py
29
29
  ```
30
30
 
31
- 3. More usage examples:
31
+ 3. **Launch the GUI (recommended)** — define, run and observe an optimization all inside one window:
32
+
33
+ ```bash
34
+ morphopt-ui # console command, available after `pip install morphopt`
35
+ # python -m morphopt.ui works too (handy when running from a source code directory)
36
+ ```
37
+
38
+ The complete UI workflow (definition part + observer part) is described in [`docs/UI_usage.md`](docs/UI_usage.md).
39
+
40
+ Further references:
32
41
 
33
42
  - Task definition guide: `docs/module_definition_guide.md`
34
43
  - Module API reference: `docs/module_reference.md`
@@ -40,9 +49,13 @@ python examples/basic/simp.py
40
49
  - `optcore` — Core package (controller, params, solver, objective, updaters)
41
50
  - `shapeopt/` — B-spline shape optimization
42
51
  - `simp/` — SIMP topology optimization
52
+ - `codesign/` — Shell co-design (shape + material)
53
+ - `ui/` — PySide6 graphical UI (definition + observer in one window)
43
54
  - `examples/` — Example tasks (bending actuator, gripper, etc.)
44
- - `docs/` — Usage guides, API reference, and theory papers
55
+ - `docs/` — Usage guides, API reference, theory papers
56
+ - [`UI_usage.md`](docs/UI_usage.md) — graphical UI user guide
45
57
  - `tests/` — Gradient checks, geometry tests, UI tests
58
+ - `ui_runs/` — runs launched from the UI and their results (`<label>_T<timestamp>/`)
46
59
 
47
60
  ## License
48
61
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "morphopt"
3
- version = "3.1.5"
3
+ version = "3.1.6"
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",
@@ -23,3 +23,7 @@ dependencies = [
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
@@ -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 the separate observer process were
6
+ therefore removed; ``view_optimization_result`` lives on the UI side now.
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)
@@ -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
 
@@ -3,26 +3,25 @@ import multiprocessing as mp
3
3
 
4
4
  class TaskOptimization:
5
5
  @classmethod
6
- def task_optimization(cls, path_result: str = None,
7
- main_filepath: str = None,
8
- device: str = 'cpu',
9
- target_iteration: int = None,
10
- restart_per_iteration: int = 20,
11
- dataqueue: mp.Queue = None):
12
-
6
+ def task_optimization(cls, path_result: str = None,
7
+ main_filepath: str = None,
8
+ device: str = 'cpu',
9
+ target_iteration: int = None,
10
+ restart_per_iteration: int = 20):
11
+ """Restart loop: run ``restart_per_iteration``-iteration chunks, then
12
+ automatically continue from the latest iteration of the same folder.
13
+ """
13
14
  import warnings
14
15
  warnings.filterwarnings("ignore", category=UserWarning)
15
16
 
16
-
17
17
  path_queue = mp.Queue()
18
18
  while True:
19
- process = mp.Process(target=cls.optmain, kwargs={'device': device,
20
- 'target_iteration': target_iteration,
21
- 'path_result': path_result,
22
- 'restart_per_iteration': restart_per_iteration,
23
- 'main_filepath': main_filepath,
24
- 'pathqueue': path_queue,
25
- 'dataqueue': dataqueue})
19
+ process = mp.Process(target=cls.optmain, kwargs={'device': device,
20
+ 'target_iteration': target_iteration,
21
+ 'path_result': path_result,
22
+ 'restart_per_iteration': restart_per_iteration,
23
+ 'main_filepath': main_filepath,
24
+ 'pathqueue': path_queue})
26
25
  process.start()
27
26
  try:
28
27
  process.join() # Wait for process to finish
@@ -36,10 +35,9 @@ class TaskOptimization:
36
35
  target_iteration = None # after first restart, always continue to the latest iteration
37
36
 
38
37
  @classmethod
39
- def optmain(cls, device='cpu', target_iteration: int = 0, path_result: str = None, restart_per_iteration: int = 20, main_filepath: str = None, pathqueue: mp.Queue = None, dataqueue: mp.Queue = None):
38
+ def optmain(cls, device='cpu', target_iteration: int = 0, path_result: str = None, restart_per_iteration: int = 20, main_filepath: str = None, pathqueue: mp.Queue = None):
40
39
  import os
41
- os.environ['KMP_DUPLICATE_LIB_OK']='True'
42
-
40
+ os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'
43
41
 
44
42
  import warnings
45
43
  warnings.filterwarnings("ignore", category=UserWarning)
@@ -50,24 +48,21 @@ class TaskOptimization:
50
48
 
51
49
  import morphopt
52
50
 
53
- filename = os.path.splitext(os.path.basename(main_filepath))[0]
51
+ filename = os.path.splitext(os.path.basename(main_filepath))[0]
54
52
  filepath = os.path.dirname(main_filepath)
55
53
  os.chdir(filepath)
56
54
  import sys
57
55
  sys.path.append(os.getcwd())
58
56
 
59
-
60
-
61
57
  Controller: morphopt.Controller = getattr(__import__(filename), 'ThisController')
62
58
 
63
59
  controller: morphopt.Controller = Controller()
64
60
  controller.restart_per_iteration = restart_per_iteration
65
- controller.dataqueue = dataqueue
66
61
  controller.optdevice = device
67
62
 
68
63
  if target_iteration == 0 or path_result is None:
69
64
  controller.start_optimization(main_filepath=main_filepath)
70
- else:
65
+ else:
71
66
  controller.restart_optimization(path_result=path_result, target_iteration=target_iteration)
72
67
 
73
68
  if pathqueue is not None:
@@ -0,0 +1,18 @@
1
+ # Compatibility shim: the results observer now lives in morphopt.ui.monitor.
2
+ # (Redesigned layout - see UIprompt.md section A.)
3
+
4
+ from .ui.monitor import ( # noqa: F401
5
+ ObserverUI as OptimizationMonitorUI,
6
+ PyVistaQWidget,
7
+ MonitorThread,
8
+ run_ui,
9
+ view_optimization_result,
10
+ )
11
+
12
+ __all__ = [
13
+ 'OptimizationMonitorUI',
14
+ 'PyVistaQWidget',
15
+ 'MonitorThread',
16
+ 'run_ui',
17
+ 'view_optimization_result',
18
+ ]
@@ -0,0 +1,37 @@
1
+ """
2
+ MorphOpt UI package.
3
+
4
+ PySide6-based design tool split into TWO parts inside ONE window:
5
+ * definition part (Workbench) -- build an optimization problem with an
6
+ Abaqus-like model tree, preview the initial geometry / load steps in a
7
+ PyVista viewport, and export/run a standard ``ThisController`` module;
8
+ * observer part (observe_panel) -- open results, start / continue / stop
9
+ optimizations, and watch geometry / metrics / load cases by polling the
10
+ result folder on disk.
11
+
12
+ Layout
13
+ ------
14
+ ui/app.py application entry point
15
+ ui/mainwindow.py top-level window hosting the two parts
16
+ ui/workbench.py definition workspace (problem-level actions live here)
17
+ ui/observe_panel.py in-window observer + run/continue/stop controls
18
+ ui/model/ data model (ProblemDefinition tree)
19
+ ui/codegen/ ProblemDefinition -> ThisController source
20
+ ui/widgets/ modeltree / editor / stepmatrix / codeeditor / viewer
21
+ ui/schemes/ per-scheme templates + generators
22
+ ui/launcher.py headless job launch / continue / result helpers
23
+
24
+ The design spec lives at the repository root in ``UIprompt.md``.
25
+ """
26
+
27
+ from __future__ import annotations
28
+
29
+
30
+ def run_app() -> int:
31
+ """Launch the MorphOpt UI (creates the QApplication and enters the loop)."""
32
+ from .app import main
33
+
34
+ return main()
35
+
36
+
37
+ __all__ = ["run_app"]
@@ -0,0 +1,6 @@
1
+ """Allow ``python -m morphopt.ui`` to launch the definition workbench."""
2
+
3
+ from .app import main
4
+
5
+ if __name__ == "__main__":
6
+ raise SystemExit(main())
@@ -0,0 +1,57 @@
1
+ """Application entry point for the MorphOpt UI (PySide6)."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import os
6
+ import sys
7
+
8
+ _DARK_QSS = """
9
+ QMainWindow, QDialog, QWidget { background-color: #121212; color: #e0e0e0; }
10
+ QMenuBar, QToolBar, QMenu { background-color: #1a1a1a; color: #e0e0e0; }
11
+ QStatusBar { background-color: #1a1a1a; color: #aaa; }
12
+ QTreeWidget, QTreeView, QTableWidget, QListWidget, QPlainTextEdit, QTextEdit {
13
+ background-color: #1c1f26; color: #e0e0e0; border: 1px solid #2b2f38; }
14
+ QHeaderView::section { background-color: #262a33; color: #e0e0e0;
15
+ border: 1px solid #2b2f38; padding: 4px; }
16
+ QTabWidget::pane { border: 1px solid #2b2f38; }
17
+ QTabBar::tab { background: #1a1a1a; color: #aaa; padding: 6px 12px;
18
+ border-top-left-radius: 4px; border-top-right-radius: 4px; }
19
+ QTabBar::tab:selected { background: #0d47a1; color: #fff; }
20
+ QPushButton { background-color: #0d47a1; color: #fff; border: none;
21
+ padding: 5px 14px; border-radius: 3px; }
22
+ QPushButton:hover { background-color: #1565c0; }
23
+ QPushButton:disabled { background-color: #333; color: #777; }
24
+ QLineEdit, QComboBox, QSpinBox { background: #262a33; color: #e0e0e0;
25
+ border: 1px solid #3a3f4a; padding: 3px; }
26
+ QCheckBox { color: #e0e0e0; }
27
+ QScrollBar:vertical { background: #1a1a1a; width: 10px; }
28
+ QScrollBar::handle:vertical { background: #3a3f4a; border-radius: 5px; }
29
+ QSplitter::handle { background: #2b2f38; }
30
+ """
31
+
32
+
33
+ def configure_environment() -> None:
34
+ """Qt / VTK friendly defaults (call before creating QApplication)."""
35
+ if sys.platform.startswith("linux"):
36
+ os.environ.setdefault("QT_QPA_PLATFORM", "xcb")
37
+ os.environ.setdefault("PYVISTA_QT_BINDING", "pyside6")
38
+ os.environ.setdefault("KMP_DUPLICATE_LIB_OK", "True")
39
+
40
+
41
+ def main() -> int:
42
+ configure_environment()
43
+
44
+ from PySide6.QtWidgets import QApplication
45
+
46
+ app = QApplication(sys.argv)
47
+ app.setStyleSheet(_DARK_QSS)
48
+
49
+ from .mainwindow import MainWindow
50
+
51
+ win = MainWindow()
52
+ win.show()
53
+ return app.exec()
54
+
55
+
56
+ if __name__ == "__main__":
57
+ raise SystemExit(main())
@@ -0,0 +1 @@
1
+ """Code generation: ProblemDefinition -> a runnable ``ThisController`` module."""