morphopt 3.1.1__py3-none-any.whl
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/__init__.py +32 -0
- morphopt/opt_runner.py +130 -0
- morphopt/optcore/baseobject.py +48 -0
- morphopt/optcore/controller.py +404 -0
- morphopt/optcore/history.py +440 -0
- morphopt/optcore/modelparams/__init__.py +4 -0
- morphopt/optcore/modelparams/base_params.py +97 -0
- morphopt/optcore/modelparams/feamodel/__init__.py +0 -0
- morphopt/optcore/modelparams/feamodel/feainterface/__init__.py +10 -0
- morphopt/optcore/modelparams/feamodel/feainterface/basefeainterface.py +50 -0
- morphopt/optcore/modelparams/feamodel/feainterface/bodyforceinterface.py +71 -0
- morphopt/optcore/modelparams/feamodel/feainterface/boundaryconditioninterface.py +59 -0
- morphopt/optcore/modelparams/feamodel/feainterface/contactinterface.py +113 -0
- morphopt/optcore/modelparams/feamodel/feainterface/coupleinterface.py +31 -0
- morphopt/optcore/modelparams/feamodel/feainterface/pointinterface.py +79 -0
- morphopt/optcore/modelparams/feamodel/feainterface/pressureinterface.py +68 -0
- morphopt/optcore/modelparams/feamodel/feainterface/referencepointinterface.py +29 -0
- morphopt/optcore/modelparams/feamodel/feainterface/springinterface.py +104 -0
- morphopt/optcore/modelparams/feamodel/feaparams.py +264 -0
- morphopt/optcore/modelparams/geometry/__init__.py +3 -0
- morphopt/optcore/modelparams/geometry/geometryinterfaces/__init__.py +1 -0
- morphopt/optcore/modelparams/geometry/geometryinterfaces/basesurfaceinterface.py +763 -0
- morphopt/optcore/modelparams/geometry/geometryinterfaces/bspsurfaceinterface.py +723 -0
- morphopt/optcore/modelparams/geometry/geometryinterfaces/cpgeosurfaceinterface.py +374 -0
- morphopt/optcore/modelparams/geometry/geometryparams.py +715 -0
- morphopt/optcore/modelparams/materials/__init__.py +1 -0
- morphopt/optcore/modelparams/materials/materialparams.py +110 -0
- morphopt/optcore/modelparams/params.py +88 -0
- morphopt/optcore/objfunc.py +248 -0
- morphopt/optcore/solver.py +159 -0
- morphopt/optcore/updaters/__init__.py +2 -0
- morphopt/optcore/updaters/base_updater.py +110 -0
- morphopt/optcore/updaters/geometry/__init__.py +2 -0
- morphopt/optcore/updaters/geometry/objectivefuncs/__init__.py +5 -0
- morphopt/optcore/updaters/geometry/objectivefuncs/basefuncs.py +117 -0
- morphopt/optcore/updaters/geometry/objectivefuncs/boundarys.py +91 -0
- morphopt/optcore/updaters/geometry/objectivefuncs/distancesurface.py +123 -0
- morphopt/optcore/updaters/geometry/objectivefuncs/shapederivative.py +179 -0
- morphopt/optcore/updaters/geometry/objectivefuncs/surfacefairness.py +40 -0
- morphopt/optcore/updaters/geometry/update_geometry.py +347 -0
- morphopt/optcore/updaters/optimizer.py +177 -0
- morphopt/optcore/updaters/updaters.py +82 -0
- morphopt/optcore/utils/plot_history_surface.py +239 -0
- morphopt/taskoptmization.py +75 -0
- morphopt/taskui.py +458 -0
- morphopt-3.1.1.dist-info/METADATA +242 -0
- morphopt-3.1.1.dist-info/RECORD +49 -0
- morphopt-3.1.1.dist-info/WHEEL +5 -0
- morphopt-3.1.1.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
|
|
2
|
+
from calendar import c
|
|
3
|
+
import math
|
|
4
|
+
import pyvista as pv
|
|
5
|
+
import torch
|
|
6
|
+
import morphopt
|
|
7
|
+
|
|
8
|
+
class SurfacesFigurePlotter:
|
|
9
|
+
|
|
10
|
+
def __init__(self, restart_path: str):
|
|
11
|
+
import importlib.util
|
|
12
|
+
torch.set_default_dtype(torch.float64)
|
|
13
|
+
torch.set_default_device('cpu')
|
|
14
|
+
spec = importlib.util.spec_from_file_location("MAIN_SCRIPT_FOR_RESTART", restart_path + '/scripts/' + 'MAIN_SCRIPT_FOR_RESTART.py')
|
|
15
|
+
MAIN_SCRIPT_FOR_RESTART = importlib.util.module_from_spec(spec)
|
|
16
|
+
spec.loader.exec_module(MAIN_SCRIPT_FOR_RESTART)
|
|
17
|
+
|
|
18
|
+
params: morphopt.Params = MAIN_SCRIPT_FOR_RESTART.ThisController.Params()
|
|
19
|
+
|
|
20
|
+
self.params = params
|
|
21
|
+
self.restart_path = restart_path
|
|
22
|
+
|
|
23
|
+
self.colors = [(40.0 / 255, 120.0 / 255, 181.0 / 255)] * self.params.geometry.num_surface
|
|
24
|
+
self.opacity = [1.0] * self.params.geometry.num_surface
|
|
25
|
+
self.opacity[0] = 0.6
|
|
26
|
+
self.boundary: tuple[float, float, float, float, float, float] = None
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def load_parameters(self, iteration: int):
|
|
30
|
+
"""
|
|
31
|
+
Load the parameters at a given iteration.
|
|
32
|
+
"""
|
|
33
|
+
self.params.geometry.load(foldpath=self.restart_path + '/log/', iteration=iteration)
|
|
34
|
+
|
|
35
|
+
def plot_surfaces(self, iteration: int,
|
|
36
|
+
colors: list[tuple[float, float, float]] | tuple[float, float, float] = None,
|
|
37
|
+
opacity: list[float] = None,
|
|
38
|
+
boundary: tuple[float, float, float, float, float, float] = None,
|
|
39
|
+
plotter=None):
|
|
40
|
+
"""
|
|
41
|
+
Plot the surfaces at a given iteration.
|
|
42
|
+
"""
|
|
43
|
+
|
|
44
|
+
if colors is None:
|
|
45
|
+
colors = self.colors
|
|
46
|
+
if opacity is None:
|
|
47
|
+
opacity = self.opacity
|
|
48
|
+
if boundary is None:
|
|
49
|
+
boundary = self.boundary
|
|
50
|
+
|
|
51
|
+
self.load_parameters(iteration=iteration)
|
|
52
|
+
|
|
53
|
+
if plotter is None:
|
|
54
|
+
plotter = pv.Plotter()
|
|
55
|
+
|
|
56
|
+
for sf in range(self.params.geometry.num_surface):
|
|
57
|
+
if sf == 0:
|
|
58
|
+
alpha = 0.6
|
|
59
|
+
else:
|
|
60
|
+
alpha = 1.0
|
|
61
|
+
if opacity is not None:
|
|
62
|
+
alpha = opacity[sf]
|
|
63
|
+
|
|
64
|
+
color_to_use = (40.0 / 255, 120.0 / 255, 181.0 / 255)
|
|
65
|
+
if colors is not None and isinstance(colors, list):
|
|
66
|
+
color_to_use = colors[sf]
|
|
67
|
+
elif colors is not None and isinstance(colors, tuple):
|
|
68
|
+
color_to_use = colors
|
|
69
|
+
|
|
70
|
+
mesh = self.params.geometry.surface_list[sf].get_mesh()
|
|
71
|
+
plotter.add_mesh(mesh, opacity=alpha, color=color_to_use,
|
|
72
|
+
diffuse=0.8, specular=0.2, ambient=0.1, specular_power=10,
|
|
73
|
+
smooth_shading=True, show_edges=False)
|
|
74
|
+
|
|
75
|
+
if boundary is not None:
|
|
76
|
+
pass
|
|
77
|
+
|
|
78
|
+
def plot_surface_rotation(self, iteration: int,
|
|
79
|
+
colors: tuple[float, float, float] = None,
|
|
80
|
+
opacity: list[float] = None,
|
|
81
|
+
boundary: tuple[float, float, float, float, float, float] = None,
|
|
82
|
+
n_frames: int = 36,
|
|
83
|
+
total_time: int = 4000,
|
|
84
|
+
view: tuple[float, float] = (45, 70),
|
|
85
|
+
output_gif: str = 'surface_rotation.gif'):
|
|
86
|
+
"""
|
|
87
|
+
Plot the surfaces at a given iteration with rotation and save as a gif.
|
|
88
|
+
|
|
89
|
+
Args:
|
|
90
|
+
iteration (int): The iteration number to plot.
|
|
91
|
+
colors (tuple): The RGB color for the surfaces.
|
|
92
|
+
opacity (list): The opacity for each surface.
|
|
93
|
+
boundary (tuple): The boundary points to plot. Should be in the form (x_min, x_max, y_min, y_max, z_min, z_max).
|
|
94
|
+
n_frames (int): The number of frames in the rotation.
|
|
95
|
+
delay (int): The delay between frames in milliseconds.
|
|
96
|
+
view (tuple): The (azimuth, elevation) angles for the view.
|
|
97
|
+
output_gif (str): The output gif file name.
|
|
98
|
+
"""
|
|
99
|
+
|
|
100
|
+
plotter = pv.Plotter(off_screen=True, window_size=[2500, 2500])
|
|
101
|
+
plotter.set_background('white')
|
|
102
|
+
plotter.enable_lightkit() # 启用光照效果
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
self.plot_surfaces(iteration=iteration, colors=colors, opacity=opacity, boundary=boundary, plotter=plotter)
|
|
106
|
+
|
|
107
|
+
plotter.enable_parallel_projection()
|
|
108
|
+
azimuth = 210
|
|
109
|
+
elevation = 20
|
|
110
|
+
plotter.view_vector((math.cos(math.radians(azimuth)) * math.cos(math.radians(elevation)),
|
|
111
|
+
math.sin(math.radians(azimuth)) * math.cos(math.radians(elevation)),
|
|
112
|
+
math.sin(math.radians(elevation))))
|
|
113
|
+
|
|
114
|
+
plotter.open_gif(output_gif)
|
|
115
|
+
plotter.camera_position = 'iso'
|
|
116
|
+
|
|
117
|
+
for i in range(n_frames):
|
|
118
|
+
plotter.write_frame()
|
|
119
|
+
plotter.camera.azimuth += 360 / n_frames
|
|
120
|
+
|
|
121
|
+
plotter.close()
|
|
122
|
+
|
|
123
|
+
def plot_history_surface(self, surface_index: int, history_index: int = 0,
|
|
124
|
+
colors: tuple[float, float, float] = None,
|
|
125
|
+
opacity: float = 0.6,
|
|
126
|
+
boundary: tuple[float, float, float, float, float, float] = None,
|
|
127
|
+
total_time: int = 4000,
|
|
128
|
+
output_gif: str = 'history_surface.gif',
|
|
129
|
+
output_jpg_foldpath: str = None):
|
|
130
|
+
"""
|
|
131
|
+
Plot the history of a surface over iterations and save as a gif.
|
|
132
|
+
|
|
133
|
+
Args:
|
|
134
|
+
surface_index (int): The index of the surface to plot.
|
|
135
|
+
history_index (int): The total history index to plot.
|
|
136
|
+
colors (tuple): The RGB color for the surface.
|
|
137
|
+
opacity (float): The opacity for the surface.
|
|
138
|
+
boundary (tuple): The boundary points to plot. Should be in the form (x_min, x_max, y_min, y_max, z_min, z_max).
|
|
139
|
+
total_time (int): The total time for the gif in milliseconds.
|
|
140
|
+
output_gif (str): The output gif file name.
|
|
141
|
+
output_jpg_foldpath (str): The folder path to save individual jpg frames. If None, frames are not saved.
|
|
142
|
+
|
|
143
|
+
"""
|
|
144
|
+
if colors is None:
|
|
145
|
+
colors = self.colors[surface_index]
|
|
146
|
+
if boundary is None:
|
|
147
|
+
boundary = self.boundary
|
|
148
|
+
|
|
149
|
+
plotter = pv.Plotter(off_screen=True, window_size=[2500, 2500])
|
|
150
|
+
plotter.set_background('white')
|
|
151
|
+
|
|
152
|
+
plotter.enable_parallel_projection()
|
|
153
|
+
azimuth = 210
|
|
154
|
+
elevation = 20
|
|
155
|
+
plotter.view_vector((math.cos(math.radians(azimuth)) * math.cos(math.radians(elevation)),
|
|
156
|
+
math.sin(math.radians(azimuth)) * math.cos(math.radians(elevation)),
|
|
157
|
+
math.sin(math.radians(elevation))))
|
|
158
|
+
plotter.enable_lightkit() # 启用光照效果
|
|
159
|
+
|
|
160
|
+
plotter.open_gif(output_gif)
|
|
161
|
+
|
|
162
|
+
for iteration in range(history_index + 1):
|
|
163
|
+
self.load_parameters(iteration=iteration)
|
|
164
|
+
plotter.clear()
|
|
165
|
+
|
|
166
|
+
mesh = self.params.geometry.surface_list[surface_index].get_mesh()
|
|
167
|
+
plotter.add_mesh(mesh, opacity=opacity, color=colors,
|
|
168
|
+
diffuse=0.8, specular=0.2, ambient=0.1, specular_power=10,
|
|
169
|
+
smooth_shading=True, show_edges=False)
|
|
170
|
+
|
|
171
|
+
if boundary is not None:
|
|
172
|
+
pass
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
plotter.write_frame()
|
|
176
|
+
|
|
177
|
+
if output_jpg_foldpath is not None:
|
|
178
|
+
plotter.screenshot(f"{output_jpg_foldpath}/iter_{iteration}.jpg")
|
|
179
|
+
|
|
180
|
+
plotter.close()
|
|
181
|
+
|
|
182
|
+
def plot_history_all_surfaces(self, history_index: int = 0,
|
|
183
|
+
colors: list[tuple[float, float, float]] = None,
|
|
184
|
+
opacity: list[float] = None,
|
|
185
|
+
boundary: tuple[float, float, float, float, float, float] = None,
|
|
186
|
+
total_time: int = 4000,
|
|
187
|
+
output_gif: str = 'history_all_surfaces.gif',
|
|
188
|
+
output_jpg_foldpath: str = None):
|
|
189
|
+
"""
|
|
190
|
+
Plot the history of all surfaces over iterations and save as a gif.
|
|
191
|
+
|
|
192
|
+
Args:
|
|
193
|
+
history_index (int): The total history index to plot.
|
|
194
|
+
colors (list): The list of RGB colors for each surface.
|
|
195
|
+
opacity (list): The list of opacities for each surface.
|
|
196
|
+
boundary (tuple): The boundary points to plot. Should be in the form (x_min, x_max, y_min, y_max, z_min, z_max).
|
|
197
|
+
total_time (int): The total time for the gif in milliseconds.
|
|
198
|
+
output_gif (str): The output gif file name.
|
|
199
|
+
output_jpg_foldpath (str): The folder path to save individual jpg frames. If None, frames are not saved.
|
|
200
|
+
"""
|
|
201
|
+
|
|
202
|
+
if colors is None:
|
|
203
|
+
colors = self.colors
|
|
204
|
+
if opacity is None:
|
|
205
|
+
opacity = self.opacity
|
|
206
|
+
if boundary is None:
|
|
207
|
+
boundary = self.boundary
|
|
208
|
+
|
|
209
|
+
plotter = pv.Plotter(off_screen=True, window_size=[2500, 2500])
|
|
210
|
+
plotter.set_background('white')
|
|
211
|
+
|
|
212
|
+
|
|
213
|
+
plotter.open_gif(output_gif)
|
|
214
|
+
|
|
215
|
+
for iteration in range(history_index + 1):
|
|
216
|
+
plotter.clear()
|
|
217
|
+
plotter.enable_lightkit() # 启用光照效果
|
|
218
|
+
self.plot_surfaces(iteration=iteration, colors=colors, opacity=opacity, boundary=boundary, plotter=plotter)
|
|
219
|
+
|
|
220
|
+
if iteration == 0:
|
|
221
|
+
plotter.enable_parallel_projection()
|
|
222
|
+
azimuth = 210
|
|
223
|
+
elevation = 20
|
|
224
|
+
plotter.view_vector((math.cos(math.radians(azimuth)) * math.cos(math.radians(elevation)),
|
|
225
|
+
math.sin(math.radians(azimuth)) * math.cos(math.radians(elevation)),
|
|
226
|
+
math.sin(math.radians(elevation))))
|
|
227
|
+
|
|
228
|
+
plotter.write_frame()
|
|
229
|
+
|
|
230
|
+
if output_jpg_foldpath is not None:
|
|
231
|
+
plotter.screenshot(f"{output_jpg_foldpath}/iter_{iteration}.jpg")
|
|
232
|
+
|
|
233
|
+
plotter.close()
|
|
234
|
+
|
|
235
|
+
if __name__ == "__main__":
|
|
236
|
+
plotter = SurfacesFigurePlotter(restart_path='Z:/Results/EXAMPLE_T20260106_165756/')
|
|
237
|
+
plotter.plot_history_all_surfaces(history_index=3,
|
|
238
|
+
output_gif='Z:/temp/example_displacement_history.gif',
|
|
239
|
+
output_jpg_foldpath='Z:/temp/')
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import multiprocessing as mp
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class TaskOptimization:
|
|
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
|
+
|
|
13
|
+
import warnings
|
|
14
|
+
warnings.filterwarnings("ignore", category=UserWarning)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
path_queue = mp.Queue()
|
|
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})
|
|
26
|
+
process.start()
|
|
27
|
+
try:
|
|
28
|
+
process.join() # Wait for process to finish
|
|
29
|
+
if process.exitcode != 0:
|
|
30
|
+
print(f"Process failed with exit code {process.exitcode}, continuing...")
|
|
31
|
+
continue
|
|
32
|
+
path_result = path_queue.get()
|
|
33
|
+
except Exception as e:
|
|
34
|
+
print(f"Error in process or queue: {e}, continuing...")
|
|
35
|
+
continue
|
|
36
|
+
target_iteration = None # after first restart, always continue to the latest iteration
|
|
37
|
+
|
|
38
|
+
@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):
|
|
40
|
+
import os
|
|
41
|
+
os.environ['KMP_DUPLICATE_LIB_OK']='True'
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
import warnings
|
|
45
|
+
warnings.filterwarnings("ignore", category=UserWarning)
|
|
46
|
+
|
|
47
|
+
import torch
|
|
48
|
+
torch.set_default_dtype(torch.float64)
|
|
49
|
+
torch.set_default_device(device)
|
|
50
|
+
|
|
51
|
+
import morphopt
|
|
52
|
+
|
|
53
|
+
filename = os.path.splitext(os.path.basename(main_filepath))[0]
|
|
54
|
+
filepath = os.path.dirname(main_filepath)
|
|
55
|
+
os.chdir(filepath)
|
|
56
|
+
import sys
|
|
57
|
+
sys.path.append(os.getcwd())
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
Controller: morphopt.Controller = getattr(__import__(filename), 'ThisController')
|
|
62
|
+
|
|
63
|
+
controller: morphopt.Controller = Controller()
|
|
64
|
+
controller.restart_per_iteration = restart_per_iteration
|
|
65
|
+
controller.dataqueue = dataqueue
|
|
66
|
+
controller.optdevice = device
|
|
67
|
+
|
|
68
|
+
if target_iteration == 0 or path_result is None:
|
|
69
|
+
controller.start_optimization(main_filepath=main_filepath)
|
|
70
|
+
else:
|
|
71
|
+
controller.restart_optimization(path_result=path_result, target_iteration=target_iteration)
|
|
72
|
+
|
|
73
|
+
if pathqueue is not None:
|
|
74
|
+
pathqueue.put(controller.path_result)
|
|
75
|
+
return controller.path_result
|