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.

Files changed (49) hide show
  1. morphopt/__init__.py +32 -0
  2. morphopt/opt_runner.py +130 -0
  3. morphopt/optcore/baseobject.py +48 -0
  4. morphopt/optcore/controller.py +404 -0
  5. morphopt/optcore/history.py +440 -0
  6. morphopt/optcore/modelparams/__init__.py +4 -0
  7. morphopt/optcore/modelparams/base_params.py +97 -0
  8. morphopt/optcore/modelparams/feamodel/__init__.py +0 -0
  9. morphopt/optcore/modelparams/feamodel/feainterface/__init__.py +10 -0
  10. morphopt/optcore/modelparams/feamodel/feainterface/basefeainterface.py +50 -0
  11. morphopt/optcore/modelparams/feamodel/feainterface/bodyforceinterface.py +71 -0
  12. morphopt/optcore/modelparams/feamodel/feainterface/boundaryconditioninterface.py +59 -0
  13. morphopt/optcore/modelparams/feamodel/feainterface/contactinterface.py +113 -0
  14. morphopt/optcore/modelparams/feamodel/feainterface/coupleinterface.py +31 -0
  15. morphopt/optcore/modelparams/feamodel/feainterface/pointinterface.py +79 -0
  16. morphopt/optcore/modelparams/feamodel/feainterface/pressureinterface.py +68 -0
  17. morphopt/optcore/modelparams/feamodel/feainterface/referencepointinterface.py +29 -0
  18. morphopt/optcore/modelparams/feamodel/feainterface/springinterface.py +104 -0
  19. morphopt/optcore/modelparams/feamodel/feaparams.py +264 -0
  20. morphopt/optcore/modelparams/geometry/__init__.py +3 -0
  21. morphopt/optcore/modelparams/geometry/geometryinterfaces/__init__.py +1 -0
  22. morphopt/optcore/modelparams/geometry/geometryinterfaces/basesurfaceinterface.py +763 -0
  23. morphopt/optcore/modelparams/geometry/geometryinterfaces/bspsurfaceinterface.py +723 -0
  24. morphopt/optcore/modelparams/geometry/geometryinterfaces/cpgeosurfaceinterface.py +374 -0
  25. morphopt/optcore/modelparams/geometry/geometryparams.py +715 -0
  26. morphopt/optcore/modelparams/materials/__init__.py +1 -0
  27. morphopt/optcore/modelparams/materials/materialparams.py +110 -0
  28. morphopt/optcore/modelparams/params.py +88 -0
  29. morphopt/optcore/objfunc.py +248 -0
  30. morphopt/optcore/solver.py +159 -0
  31. morphopt/optcore/updaters/__init__.py +2 -0
  32. morphopt/optcore/updaters/base_updater.py +110 -0
  33. morphopt/optcore/updaters/geometry/__init__.py +2 -0
  34. morphopt/optcore/updaters/geometry/objectivefuncs/__init__.py +5 -0
  35. morphopt/optcore/updaters/geometry/objectivefuncs/basefuncs.py +117 -0
  36. morphopt/optcore/updaters/geometry/objectivefuncs/boundarys.py +91 -0
  37. morphopt/optcore/updaters/geometry/objectivefuncs/distancesurface.py +123 -0
  38. morphopt/optcore/updaters/geometry/objectivefuncs/shapederivative.py +179 -0
  39. morphopt/optcore/updaters/geometry/objectivefuncs/surfacefairness.py +40 -0
  40. morphopt/optcore/updaters/geometry/update_geometry.py +347 -0
  41. morphopt/optcore/updaters/optimizer.py +177 -0
  42. morphopt/optcore/updaters/updaters.py +82 -0
  43. morphopt/optcore/utils/plot_history_surface.py +239 -0
  44. morphopt/taskoptmization.py +75 -0
  45. morphopt/taskui.py +458 -0
  46. morphopt-3.1.1.dist-info/METADATA +242 -0
  47. morphopt-3.1.1.dist-info/RECORD +49 -0
  48. morphopt-3.1.1.dist-info/WHEEL +5 -0
  49. morphopt-3.1.1.dist-info/top_level.txt +1 -0
@@ -0,0 +1 @@
1
+ from .materialparams import Materials
@@ -0,0 +1,110 @@
1
+ import torch
2
+ from torch._refs import to
3
+
4
+ import torchfea
5
+ from ..base_params import BaseParams
6
+
7
+ class Materials(BaseParams):
8
+ """
9
+ Class to handle the materials of the morphable model.
10
+ """
11
+
12
+ def __init__(self, mu: float, kappa: float, density: float) -> None:
13
+ """
14
+ Initialize the Materials class.
15
+
16
+ Args:
17
+ mu (float): The shear modulus of the material.
18
+ kappa (float): The bulk modulus of the material.
19
+ """
20
+ super().__init__()
21
+ self._mu: float
22
+ self._kappa: float
23
+ self._density: float
24
+
25
+ self.mu = mu
26
+ self.kappa = kappa
27
+ self.density = density
28
+
29
+ @property
30
+ def mu(self) -> float:
31
+ """
32
+ Get the shear modulus.
33
+
34
+ Returns:
35
+ float: The shear modulus.
36
+ """
37
+ return self._mu
38
+
39
+ @mu.setter
40
+ def mu(self, value: float) -> None:
41
+ """
42
+ Set the shear modulus.
43
+
44
+ Args:
45
+ value (float): The new shear modulus.
46
+ """
47
+ self._mu = float(value)
48
+
49
+ @property
50
+ def kappa(self) -> float:
51
+ """
52
+ Get the bulk modulus.
53
+
54
+ Returns:
55
+ float: The bulk modulus.
56
+ """
57
+ return self._kappa
58
+
59
+ @kappa.setter
60
+ def kappa(self, value: float) -> None:
61
+ """
62
+ Set the bulk modulus.
63
+
64
+ Args:
65
+ value (float): The new bulk modulus.
66
+ """
67
+ self._kappa = float(value)
68
+
69
+ @property
70
+ def density(self) -> float:
71
+ """
72
+ Get the density.
73
+
74
+ Returns:
75
+ float: The density.
76
+ """
77
+ return self._density
78
+
79
+ @density.setter
80
+ def density(self, value: float) -> None:
81
+ """
82
+ Set the density.
83
+
84
+ Args:
85
+ value (float): The new density.
86
+ """
87
+ self._density = float(value)
88
+
89
+ def get_ratio(self, nodes: torch.Tensor) -> float:
90
+ """
91
+ Get the ratio of maximum to minimum modulus.
92
+
93
+ Returns:
94
+ float: The ratio of maximum to minimum modulus.
95
+ """
96
+ return 1.0
97
+
98
+ def set_materials(self, fe: torchfea.FEAController) -> None:
99
+ """
100
+ Set the materials of the FEA model.
101
+
102
+ Args:
103
+ fe (torchfea.FEAController): The FEA controller.
104
+ """
105
+ elements = fe.assembly.get_part('final_model').elems['element-0']
106
+ mu = self.mu
107
+ kappa = self.kappa
108
+ materials = torchfea.materials.NeoHookean(mu=mu, kappa=kappa)
109
+ elements.set_materials(materials)
110
+ elements.density = self.density
@@ -0,0 +1,88 @@
1
+
2
+ from ..baseobject import BaseObject
3
+ from .feamodel.feaparams import FEAParams
4
+ from .geometry.geometryparams import GeometryParams
5
+ from .materials.materialparams import Materials
6
+ class Params(BaseObject):
7
+ """
8
+ Class to handle the parameters of the model.
9
+ """
10
+ def __init__(self, surfaces: GeometryParams, feamodel: FEAParams, materials: Materials) -> None:
11
+ """
12
+ Initialize the Params class.
13
+ """
14
+ self.geometry = surfaces
15
+ """
16
+ Surfaces: An instance of the Surfaces class from the ModelParams module.
17
+ """
18
+ self.feamodel = feamodel
19
+ """
20
+ Loads: An instance of the Loads class from the ModelParams module.
21
+ """
22
+ self.materials = materials
23
+ """
24
+ Materials: An instance of the Materials class from the ModelParams module.
25
+ """
26
+
27
+ def reinitialize(self, iteration: int) -> None:
28
+ """
29
+ reInitialize the parameters.
30
+ """
31
+ self.geometry.reinitialize(iteration=iteration)
32
+ self.feamodel.reinitialize(iteration=iteration)
33
+ self.materials.reinitialize(iteration=iteration)
34
+
35
+ def initialize(self):
36
+ """
37
+ Initialize the parameters.
38
+ """
39
+ self.geometry.initialize()
40
+ self.feamodel.initialize()
41
+ self.materials.initialize()
42
+
43
+
44
+ def save(self, foldpath: str, iteration: int) -> None:
45
+ """
46
+ Save the parameters to a file.
47
+
48
+ Args:
49
+ foldpath (str): The path to save the parameters.
50
+ """
51
+ self.geometry.save(foldpath=foldpath, iteration=iteration)
52
+ self.feamodel.save(foldpath=foldpath, iteration=iteration)
53
+ self.materials.save(foldpath=foldpath, iteration=iteration)
54
+
55
+ def load(self, foldpath: str, iteration: int) -> None:
56
+ """
57
+ Load the parameters from a file.
58
+
59
+ Args:
60
+ foldpath (str): The path to load the parameters from.
61
+ """
62
+ self.geometry.load(foldpath=foldpath, iteration=iteration)
63
+ # self.feamodel.load(foldpath=foldpath, iteration=iteration)
64
+ # self.materials.load(foldpath=foldpath, iteration=iteration)
65
+
66
+ def export_data(self, filepath: str):
67
+ """
68
+ Export the data of parameters to file(s).
69
+
70
+ Args:
71
+ filepath (str): The path to export the data.
72
+ """
73
+ self.geometry._export_data(filepath=filepath)
74
+ self.feamodel._export_data(foldpath=filepath)
75
+ self.materials._export_data(foldpath=filepath)
76
+
77
+ def pathlog_required(self) -> list[str]:
78
+ """
79
+ Allocate the path for saving data.
80
+
81
+ Args:
82
+ foldpath (str): The path to allocate.
83
+ """
84
+ paths = []
85
+ paths += self.geometry.pathlog_required()
86
+ paths += self.feamodel.pathlog_required()
87
+ paths += self.materials.pathlog_required()
88
+ return paths
@@ -0,0 +1,248 @@
1
+ import math
2
+ import torchfea
3
+ import numpy as np
4
+ import torch
5
+ import scipy.sparse as sp
6
+ import pypardiso
7
+ import morphopt
8
+
9
+ from .baseobject import BaseObject
10
+
11
+ class ObjectiveFunction(BaseObject):
12
+ """
13
+ The objective functions in morphopt.
14
+ """
15
+
16
+ def __init__(self):
17
+ self.fe: torchfea.FEAController = None
18
+ """
19
+ The FEA solver instance.
20
+ """
21
+
22
+ self.inp: torchfea.FEA_INP = None
23
+ """
24
+ The FEA .inp file.
25
+ """
26
+
27
+ self.U: torch.Tensor
28
+ """
29
+ The displacement field.
30
+ [shape: (num_tasks, num_dofs)]
31
+ """
32
+
33
+ self.ADJu: torch.Tensor
34
+ """
35
+ The first adjoint displacement field.
36
+ [shape: (num_tasks, num_dofs)]
37
+ """
38
+
39
+ self.K_sp: list[sp.csr_matrix]
40
+ """
41
+ The sparse stiffness matrices.
42
+ [shape: (num_tasks,)]
43
+ """
44
+
45
+ self.K_solver: list[pypardiso.PyPardisoSolver]
46
+ """
47
+ The solvers for the stiffness matrix.
48
+ [shape: (num_tasks,)]
49
+ """
50
+
51
+ def get_objective(self, *args, **kwargs) -> torch.Tensor:
52
+ """
53
+ Get the value of the objective function.
54
+
55
+ Args:
56
+ *args: Positional arguments.
57
+ **kwargs: Keyword arguments.
58
+
59
+ Returns:
60
+ torch.Tensor: The value of the objective function.
61
+ """
62
+ raise NotImplementedError("This method should be overridden by subclasses.")
63
+
64
+ def get_metrics(self) -> list[float]:
65
+ """
66
+ Get custom metrics for display.
67
+
68
+ Returns:
69
+ list[float]: A list of metric values.
70
+ """
71
+ return []
72
+
73
+ @property
74
+ def num_tasks(self) -> int:
75
+ """
76
+ Get the number of tasks.
77
+ """
78
+ return self.U.shape[0]
79
+
80
+ def pathlog_required(self):
81
+ return ['deformation']
82
+
83
+ def calculate_adjoint(self, *args, **kwargs) -> torch.Tensor:
84
+ """
85
+ Calculate the adjoint variables.
86
+ """
87
+ raise NotImplementedError("This method should be overridden by subclasses.")
88
+
89
+ def calculate_adjoint_problem(self, *args, **kwargs) -> torch.Tensor:
90
+ """
91
+ Calculate the linear factor of the objective function.
92
+ """
93
+
94
+ def closure_JdU(U: torch.Tensor) -> torch.Tensor:
95
+ U0 = self.U
96
+ self.U = U
97
+ obj = self.get_objective()
98
+ self.U = U0
99
+ return obj
100
+
101
+ ADJFu_now: torch.Tensor = -torch.autograd.functional.jacobian(closure_JdU, self.U.detach().clone())
102
+
103
+ ADJu = []
104
+ K_sp_list = []
105
+ K_solver_list = []
106
+ for step_index in range(self.num_tasks):
107
+
108
+ # set the loads
109
+ morphopt.controller.params.feamodel.process_fea(fe=self.fe, step_index=step_index)
110
+
111
+ # region get the decomposed stiffness matrix
112
+ R, K_indices, K_values = self.fe.assembly.assemble_Stiffness_Matrix(GC=self.U[step_index].to(self.fe.assembly.device))
113
+ K_values = K_values.cpu().numpy()
114
+ K_indices = K_indices.cpu().numpy()
115
+ K_sp = sp.coo_matrix(
116
+ (K_values,
117
+ (K_indices[0], K_indices[1])), dtype=np.float64,
118
+ shape=(self.fe.assembly.GC.shape[0], self.fe.assembly.GC.shape[0])).tocsr()
119
+ K_solver = pypardiso.PyPardisoSolver()
120
+ K_solver.factorize(K_sp)
121
+
122
+ K_sp_list.append(K_sp)
123
+ K_solver_list.append(K_solver)
124
+
125
+ # endregion
126
+
127
+ # region calculate the adjoint variable
128
+
129
+ ADJu_now = torch.from_numpy(K_solver.solve(K_sp, ADJFu_now[step_index].cpu().numpy())).cpu()
130
+ ADJu.append(ADJu_now)
131
+ # endregion
132
+
133
+ self.ADJu = torch.stack(ADJu, dim=0).cpu()
134
+ self.K_sp = K_sp_list
135
+ self.K_solver = K_solver_list
136
+
137
+ def __str__(self) -> str:
138
+
139
+ result = ["FE_result Summary:"]
140
+
141
+ for i in range(self.num_tasks):
142
+ result.append(f"=================================Task {i+1}=================================")
143
+
144
+
145
+ # 格式化位移向量(一维)
146
+ u_vector = self.U[i][-6:].tolist()
147
+ u_str = " ".join([f"{x:.6f}" for x in u_vector])
148
+ result.append(f" Displacement U: {u_str}")
149
+
150
+ # # 格式化Jacobian矩阵(二维)
151
+ # if self.Udp is not None:
152
+ # matrix = self.Udp[i][:, -6:].T.tolist() # 二维矩阵
153
+ # result.append(f" Jacobian Udp:")
154
+ # # 格式化并添加矩阵每行
155
+ # formatted = format_matrix(matrix, indent=4)
156
+ # result.extend(formatted)
157
+
158
+ # # 格式化UdF矩阵(二维)
159
+ # if self.UdF is not None:
160
+ # matrix = self.UdF[i][:, -6:].tolist() # 二维矩阵
161
+ # result.append(f" UdF:")
162
+ # formatted = format_matrix(matrix, indent=4)
163
+ # result.extend(formatted)
164
+
165
+ result.append(f"============================================================================")
166
+
167
+ return "\n".join(result)
168
+
169
+ def __getitem__(self, key):
170
+ """
171
+ Get the attribute with the given key.
172
+
173
+ Parameters:
174
+ key: The key of the attribute to get.
175
+
176
+ Returns:
177
+ The attribute value.
178
+
179
+ Raises:
180
+ KeyError: If the key is not found.
181
+ """
182
+ if hasattr(self, key):
183
+ return getattr(self, key)
184
+ else:
185
+ raise KeyError(f"'{key}' not found in FE_result")
186
+
187
+ def save(self, foldpath: str, iteration: int, insname: str = 'final_model', surface: str = 'surface_0_All') -> None:
188
+ """
189
+ Save the figures of the FEA results.
190
+
191
+ Parameters:
192
+ foldpath (str): The path to save the figures.
193
+ iteration (int): The current iteration number.
194
+ """
195
+ ins = self.fe.assembly.get_instance(insname)
196
+ surfaces = [surface]
197
+ surface_elements: list[torchfea.elements.BaseSurface] = []
198
+ for i in range(len(surfaces)):
199
+ surface_elements = surface_elements + ins.surfaces.get_elements(surfaces[i])
200
+
201
+ surface_connections = [surface_elements[i].surf_elems_circ.cpu().numpy() for i in range(len(surface_elements))]
202
+
203
+ for case in range(self.num_tasks):
204
+ deformed_nodes = (ins.nodes + self.fe.assembly._GC2RGC(self.U[case].to(ins.nodes.device))[ins._RGC_index]).detach().cpu().numpy()
205
+
206
+ import pyvista as pv
207
+
208
+ plotter = pv.Plotter(off_screen=True, window_size=(1200, 1200))
209
+
210
+ # Create faces list for pyvista
211
+ faces = []
212
+ for connection in surface_connections:
213
+ for face in connection:
214
+ if -1 not in face:
215
+ faces.append([len(face)] + list(face))
216
+
217
+ # Create pyvista mesh
218
+ mesh = pv.PolyData(deformed_nodes, faces)
219
+ plotter.add_mesh(mesh, color=(40.0/255, 120.0/255, 181.0/255), opacity=1.0)
220
+
221
+ x_min, x_max = deformed_nodes[:,0].min().item(), deformed_nodes[:,0].max().item()
222
+ y_min, y_max = deformed_nodes[:,1].min().item(), deformed_nodes[:,1].max().item()
223
+ z_min, z_max = deformed_nodes[:,2].min().item(), deformed_nodes[:,2].max().item()
224
+
225
+ # Add some padding to the bounds
226
+ padding = 0.05 * max(x_max-x_min, y_max-y_min, z_max-z_min)
227
+
228
+ plotter.show_bounds(xtitle='X', ytitle='Y', ztitle='Z', color='black',
229
+ bounds=[x_min-padding, x_max+padding,
230
+ y_min-padding, y_max+padding,
231
+ z_min-padding, z_max+padding])
232
+
233
+ # Approximate view
234
+ plotter.set_background('white')
235
+ plotter.enable_parallel_projection()
236
+ azimuth = 210
237
+ elevation = 20
238
+ plotter.view_vector((math.cos(math.radians(azimuth)) * math.cos(math.radians(elevation)),
239
+ math.sin(math.radians(azimuth)) * math.cos(math.radians(elevation)),
240
+ math.sin(math.radians(elevation))))
241
+
242
+ # Save the figure as a PNG file
243
+ plotter.screenshot(f"{foldpath}/{self.pathlog_required()[0]}/task_{case}_iter_{iteration}.png")
244
+
245
+ # Save the deformed mesh as an OBJ file
246
+ obj_filepath = f"{foldpath}/{self.pathlog_required()[0]}/task_{case}_iter_{iteration}.obj"
247
+ mesh.save(obj_filepath)
248
+ plotter.close()
@@ -0,0 +1,159 @@
1
+
2
+ import numpy as np
3
+ import torch
4
+ import copy
5
+ import torchfea
6
+ import multiprocessing as mp
7
+
8
+ from .modelparams import Params, FEAParams, Materials
9
+
10
+ from .baseobject import BaseObject
11
+ import morphopt
12
+ class MorphSolver(BaseObject):
13
+ """
14
+ This class is responsible for solving the FEA and get the displacement of the soft robot.
15
+ """
16
+
17
+
18
+ def __init__(self, params: Params, num_process: int = 4, available_gpus: list[str] = None, task_index_list: list[list[int]] = None):
19
+ """
20
+ Initialize the Solver class with a list of pressure values.
21
+
22
+ Parameters:
23
+ params (Params):
24
+ num_process (int): The number of processes to use for parallel computation.
25
+ """
26
+
27
+ super().__init__()
28
+
29
+ self.params: Params = params
30
+ """
31
+ Pressures: An instance of the params of the optimization problem.
32
+ """
33
+
34
+ self.num_process = num_process
35
+ """
36
+ int: The number of processes to use for parallel computation.
37
+ """
38
+
39
+ if available_gpus is None:
40
+ self.available_gpus = ['cuda:%d' % i for i in range(torch.cuda.device_count())]
41
+ else:
42
+ self.available_gpus = available_gpus
43
+
44
+ self.task_index_list = task_index_list
45
+ """
46
+ list[list[int]]: A list of task indices for each process.
47
+ """
48
+
49
+ def initialize(self):
50
+ if self.task_index_list is None:
51
+ self.task_index_list = []
52
+ for i in range(morphopt.controller.params.feamodel.num_load_steps):
53
+ self.task_index_list.append([i])
54
+
55
+
56
+
57
+ def reinitialize(self, iteration: int) -> None:
58
+ """
59
+ Reinitialize the solver for a new iteration.
60
+
61
+ Parameters:
62
+ iteration (int): The current iteration number.
63
+ """
64
+ pass
65
+
66
+ def solve(self):
67
+ """
68
+ Solve the optimization problem using the specified solver.
69
+
70
+ Returns:
71
+ tuple: the displacement field and its derivatives:
72
+ - fe (torchfea.FEAController): An instance of the FEA_Main class with the given input parameters.
73
+ - GC0 (list[torch.Tensor]): The displacement field at the reference point.
74
+ - Udp0 (list[torch.Tensor]): The displacement field at the reference point with respect to the pressure.
75
+ - GCv (list[torch.Tensor]): The first adjoint displacement field.
76
+ - GCw (list[torch.Tensor]): The second adjoint displacement field.
77
+ """
78
+
79
+ # multiprocess FEA
80
+
81
+ fe_cpu = copy.deepcopy(morphopt.controller.objfun.fe)
82
+ fe_cpu.change_device(torch.device('cpu'))
83
+
84
+ # self._solve_FEA(fe=fe_cpu,
85
+ # feamodel=self.params.feamodel,
86
+ # task_index=self.task_index_list[0],
87
+ # available_gpus=self.available_gpus)
88
+
89
+ pools = morphopt.controller.pools
90
+ result = []
91
+ for i in range(len(self.task_index_list)):
92
+ result.append(
93
+ pools.apply_async(self._solve_FEA,
94
+ kwds={'fe': fe_cpu,
95
+ 'feamodel': self.params.feamodel,
96
+ 'task_index': self.task_index_list[i],
97
+ 'available_gpus': self.available_gpus}))
98
+
99
+ # get the result
100
+ U0 = []
101
+ list_number = []
102
+ for i in range(len(result)):
103
+ U0 += result[i].get()
104
+ list_number += self.task_index_list[i]
105
+ list_number = np.array(list_number).flatten()
106
+
107
+ Uresult = torch.tensor(U0).to(torch.float64)[list_number]
108
+ del fe_cpu
109
+ return Uresult
110
+
111
+
112
+ @classmethod
113
+ def _solve_FEA(cls, fe: torchfea.FEAController,
114
+ feamodel: FEAParams,
115
+ task_index: list[int],
116
+ available_gpus: list[str],
117
+ U_guess: np.ndarray = None):
118
+ import os
119
+ os.environ['KMP_DUPLICATE_LIB_OK']='True'
120
+ import sys
121
+ import torch
122
+ sys.path.append(os.getcwd())
123
+
124
+ current_process_name = mp.current_process().name
125
+ try:
126
+ pool_id = int(current_process_name[-1])
127
+ except:
128
+ pool_id = 0
129
+
130
+ if len(available_gpus) > 0:
131
+ cuda_now = (pool_id+1) % len(available_gpus)
132
+ torch.set_default_device(available_gpus[cuda_now])
133
+ device_now = available_gpus[cuda_now]
134
+ print("Process %s use GPU: %s" % (current_process_name, available_gpus[cuda_now]))
135
+ else:
136
+ torch.set_default_device('cpu')
137
+ device_now = 'cpu'
138
+ print("Process %s use CPU" % (current_process_name))
139
+
140
+ # torch.set_default_device(torch.device('cuda:0'))
141
+ torch.set_default_dtype(torch.float64)
142
+ torch.cuda.empty_cache()
143
+ # construct the FEA
144
+ fe.change_device(device_now)
145
+
146
+ if U_guess is not None:
147
+ U0 = torch.from_numpy(U_guess).to(torch.float64).to(fe.assembly.device)
148
+ else:
149
+ U0 = fe.assembly.GC.to(torch.get_default_device())
150
+
151
+ result_list = []
152
+ for i in range(len(task_index)):
153
+ feamodel.process_fea(fe=fe, step_index=task_index[i])
154
+ result: torchfea.solver.StaticResult = fe.solve(GC0=U0.to(torch.get_default_device()), if_initialize=False)
155
+
156
+ U0 = result.GC.detach()
157
+ Unow = U0.cpu().numpy()
158
+ result_list.append(Unow)
159
+ return result_list
@@ -0,0 +1,2 @@
1
+ from . import geometry
2
+ from .updaters import Updaters