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.
- {morphopt-3.1.5 → morphopt-3.1.6}/PKG-INFO +22 -9
- {morphopt-3.1.5 → morphopt-3.1.6}/README.md +20 -7
- {morphopt-3.1.5 → morphopt-3.1.6}/pyproject.toml +6 -2
- {morphopt-3.1.5 → morphopt-3.1.6}/setup.cfg +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/__init__.py +1 -1
- morphopt-3.1.6/src/morphopt/opt_runner.py +82 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/basesurfaceinterface.py +1 -23
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/bspsurfaceinterface.py +5 -10
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/cpgeosurfaceinterface.py +6 -8
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryparams.py +1 -1
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/distancesurface.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/shapederivative.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/taskoptmization.py +18 -23
- morphopt-3.1.6/src/morphopt/taskui.py +18 -0
- morphopt-3.1.6/src/morphopt/ui/__init__.py +37 -0
- morphopt-3.1.6/src/morphopt/ui/__main__.py +6 -0
- morphopt-3.1.6/src/morphopt/ui/app.py +57 -0
- morphopt-3.1.6/src/morphopt/ui/codegen/__init__.py +1 -0
- morphopt-3.1.6/src/morphopt/ui/codegen/generator.py +367 -0
- morphopt-3.1.6/src/morphopt/ui/codegen/objective_templates.py +52 -0
- morphopt-3.1.6/src/morphopt/ui/launcher.py +153 -0
- morphopt-3.1.6/src/morphopt/ui/mainwindow.py +146 -0
- morphopt-3.1.6/src/morphopt/ui/model/__init__.py +16 -0
- morphopt-3.1.6/src/morphopt/ui/model/loaders.py +32 -0
- morphopt-3.1.6/src/morphopt/ui/model/problem.py +170 -0
- morphopt-3.1.6/src/morphopt/ui/model/schemas.py +489 -0
- morphopt-3.1.6/src/morphopt/ui/monitor.py +558 -0
- morphopt-3.1.6/src/morphopt/ui/observe_panel.py +533 -0
- morphopt-3.1.6/src/morphopt/ui/schemes/__init__.py +14 -0
- morphopt-3.1.6/src/morphopt/ui/schemes/base.py +101 -0
- morphopt-3.1.6/src/morphopt/ui/schemes/codesign.py +173 -0
- morphopt-3.1.6/src/morphopt/ui/schemes/shapeopt.py +127 -0
- morphopt-3.1.6/src/morphopt/ui/schemes/simp.py +115 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/__init__.py +1 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/codeeditor.py +207 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/editor.py +305 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/model_tree.py +282 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/objective_editor.py +141 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/param_form.py +152 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/solver_editor.py +181 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/stepmatrix.py +207 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/updater_editor.py +214 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/values.py +63 -0
- morphopt-3.1.6/src/morphopt/ui/widgets/viewer.py +252 -0
- morphopt-3.1.6/src/morphopt/ui/workbench.py +313 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt.egg-info/PKG-INFO +22 -9
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt.egg-info/SOURCES.txt +32 -0
- morphopt-3.1.6/src/morphopt.egg-info/entry_points.txt +2 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt.egg-info/requires.txt +1 -1
- {morphopt-3.1.5 → morphopt-3.1.6}/tests/test_ui.py +0 -0
- morphopt-3.1.5/src/morphopt/opt_runner.py +0 -143
- morphopt-3.1.5/src/morphopt/taskui.py +0 -494
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/__init__.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/constraints.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/feaparams.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/geometry.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/material.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/codesign/params.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/__init__.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/baseobject.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/controller.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/history.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/__init__.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/baseparam.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/__init__.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/basefeainterface.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/bodyforceinterface.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/boundaryconditioninterface.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/contactinterface.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/coupleinterface.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/pointinterface.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/pressureinterface.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/referencepointinterface.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feainterface/springinterface.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/feaparams.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/geometry.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/materials.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/modelparams/params.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/objfunc.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/solver.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/optcore/updaters.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/__init__.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/__init__.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/__init__.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/basefuncs.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/boundarys.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/surfacefairness.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objectivefuncs/volumemaximization.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/objfunc.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/update_geometry.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/__init__.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/__init__.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/basefuncs.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/boundarys.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/densityfield.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/sensitivity.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/objectivefuncs/volfrac.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/simpmaterial.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/solver.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/simp/update_material.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/utils/__init__.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/utils/gradient_check.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/utils/history_read.py +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt.egg-info/dependency_links.txt +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt.egg-info/top_level.txt +0 -0
- {morphopt-3.1.5 → morphopt-3.1.6}/tests/test_fixedGeometry.py +0 -0
- {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.
|
|
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:
|
|
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
|
|
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/
|
|
48
|
+
# Shape optimization (pneumatic bending actuator)
|
|
49
|
+
python examples/bendingactuator.py
|
|
50
50
|
|
|
51
|
-
# SIMP topology optimization
|
|
52
|
-
python examples/
|
|
51
|
+
# SIMP topology optimization (compliant gripper)
|
|
52
|
+
python examples/gripper.py
|
|
53
53
|
```
|
|
54
54
|
|
|
55
|
-
3.
|
|
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,
|
|
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
|
|
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/
|
|
24
|
+
# Shape optimization (pneumatic bending actuator)
|
|
25
|
+
python examples/bendingactuator.py
|
|
26
26
|
|
|
27
|
-
# SIMP topology optimization
|
|
28
|
-
python examples/
|
|
27
|
+
# SIMP topology optimization (compliant gripper)
|
|
28
|
+
python examples/gripper.py
|
|
29
29
|
```
|
|
30
30
|
|
|
31
|
-
3.
|
|
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,
|
|
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.
|
|
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
|
-
"
|
|
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
|
|
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)
|
{morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/basesurfaceinterface.py
RENAMED
|
@@ -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,
|
|
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)
|
{morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/bspsurfaceinterface.py
RENAMED
|
@@ -36,7 +36,7 @@ class BspInterface(CpBasedInterface):
|
|
|
36
36
|
|
|
37
37
|
def build(self):
|
|
38
38
|
"""
|
|
39
|
-
构建版本 - 改用 addBSplineSurface +
|
|
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,
|
|
396
|
-
super().__init__(surface
|
|
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,
|
|
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,
|
|
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
|
{morphopt-3.1.5 → morphopt-3.1.6}/src/morphopt/shapeopt/geometryinterfaces/cpgeosurfaceinterface.py
RENAMED
|
@@ -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,
|
|
24
|
-
super().__init__(surface
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
584
|
+
Apply the constraints (e.g. the surface constraint) of the surfaces.
|
|
585
585
|
"""
|
|
586
586
|
pass
|
|
587
587
|
|
|
File without changes
|
|
File without changes
|
|
@@ -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
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
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,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."""
|