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,264 @@
1
+
2
+ import torchfea
3
+ import numpy as np
4
+ import torch
5
+
6
+ from ..base_params import BaseParams
7
+ from .feainterface.basefeainterface import BaseFEAInterface
8
+
9
+ from torchfea import FEA_INP, FEAController
10
+
11
+ class FEAParams(BaseParams):
12
+ """
13
+ Class to handle the loads in the model.
14
+ """
15
+ from .feainterface import PressureInterface
16
+ from .feainterface import ContactInterface, ContactSelfInterface
17
+ from .feainterface import ConcentratedForceInterface, ConcentratedMomentInterface
18
+ from .feainterface import SpringToGroundInterface, SpringBetweenRPsInterface
19
+ from .feainterface import BoundaryConditionInterface, BoundaryConditionRPInterface
20
+ from .feainterface import CoupleInterface
21
+ from .feainterface import ReferencePointInterface
22
+ from .feainterface import BodyforceInterface
23
+ def __init__(self):
24
+ """
25
+ Initialize the Loads class.
26
+ """
27
+ self.feainterfaces: dict[str, BaseFEAInterface] = {}
28
+ """loadinterfaces (dict): A dictionary to hold the load interfaces."""
29
+
30
+ self.fea_steps_params: list[dict[str, list[float]]] = []
31
+ """load_steps (list): A list to hold the load steps."""
32
+
33
+ self.define_interface()
34
+ self.define_steps()
35
+
36
+ def define_interface(self):
37
+ pass
38
+
39
+ def define_steps(self):
40
+ pass
41
+
42
+
43
+ def add_instance_from_inp(self, fe: torchfea.FEAController, inp_path: str, part_name: str, instance_name: str, translation: list[float] = None, part_name_new: str = None, instance_name_new: str = None) -> None:
44
+ """
45
+ Add a part and instance into the current FE assembly by reading an external INP file.
46
+
47
+ Args:
48
+ fe: Target FEAController to modify.
49
+ inp_path: Absolute path to the external INP file.
50
+ part_name: Name of the part in the external model to import.
51
+ instance_name: Name to register for the created instance in the current assembly.
52
+ translation: Optional [Tx, Ty, Tz] translation applied to the created instance.
53
+ part_name_new: Optional new name for the imported part in the current assembly.
54
+ instance_name_new: Optional new name for the created instance in the current assembly.
55
+ """
56
+ if part_name_new is None:
57
+ part_name_new = part_name
58
+ if instance_name_new is None:
59
+ instance_name_new = instance_name
60
+
61
+ ext_inp = torchfea.FEA_INP()
62
+ ext_inp.read_inp(inp_path)
63
+ fe_ext = torchfea.from_inp(ext_inp)
64
+ part = fe_ext.assembly.get_part(part_name)
65
+ fe.assembly.add_part(part, name=part_name_new)
66
+ fe.assembly.add_instance(torchfea.Instance(part=part), name=instance_name_new)
67
+ inst = fe.assembly.get_instance(instance_name_new)
68
+ trans = translation if translation is not None else [0.0, 0.0, 0.0]
69
+ inst._translation = torch.tensor(trans)
70
+
71
+ def add_fea_interface(self, fea_interface: BaseFEAInterface, name: str = None) -> str:
72
+ """
73
+ Add a load interface to the load interfaces dictionary.
74
+
75
+ Args:
76
+ name (str): The name of the load interface.
77
+ load_interface (BaseLoadInterface): The load interface object.
78
+ Returns:
79
+ str: The name of the load interface.
80
+ """
81
+ if name in self.feainterfaces:
82
+ raise ValueError(f"Load interface with name '{name}' already exists.")
83
+ if name is None:
84
+ name0 = fea_interface.__class__.__name__
85
+ ind = 0
86
+ while '%s_%d'%(name0,ind) in self.feainterfaces:
87
+ ind += 1
88
+ name = '%s_%d'%(name0,ind)
89
+
90
+ self.feainterfaces[name] = fea_interface
91
+ fea_interface._name = name
92
+ return name
93
+
94
+ def set_step_num(self, num_steps: int) -> None:
95
+ """
96
+ Set the number of load steps.
97
+
98
+ Args:
99
+ num_steps (int): The number of load steps.
100
+ """
101
+ self.fea_steps_params = []
102
+ for _ in range(num_steps):
103
+ load_step = {}
104
+ for name, load_interface in self.feainterfaces.items():
105
+ load_step[name] = load_interface._values.copy()
106
+ self.fea_steps_params.append(load_step)
107
+
108
+ def set_step_params(self, step_index: int, load_name: str, values: list[float]) -> None:
109
+ """
110
+ Set the load parameters for a specific load step.
111
+
112
+ Args:
113
+ step_index (int): The index of the load step.
114
+ load_name (str): The name of the load interface.
115
+ values (list[float]): The load parameter values.
116
+ """
117
+ if step_index < 0 or step_index >= len(self.fea_steps_params):
118
+ raise IndexError("step_index out of range.")
119
+ if load_name not in self.feainterfaces:
120
+ raise KeyError(f"Load interface with name '{load_name}' does not exist.")
121
+ self.fea_steps_params[step_index][load_name] = values
122
+
123
+ def reinitialize(self, iteration, *args, **kwargs):
124
+ # Sort the load interfaces and load steps parameters by their keys
125
+ sorted_fea_interfaces = dict(sorted(self.feainterfaces.items()))
126
+ sorted_fea_steps_params = [dict(sorted(step.items())) for step in self.fea_steps_params]
127
+
128
+ # Update the dictionaries with the sorted versions
129
+ self.feainterfaces = sorted_fea_interfaces
130
+ self.fea_steps_params = sorted_fea_steps_params
131
+
132
+ @property
133
+ def num_load_steps(self) -> int:
134
+ """
135
+ Get the number of load steps.
136
+
137
+ Returns:
138
+ int: The number of load steps.
139
+ """
140
+ return len(self.fea_steps_params)
141
+
142
+ def create_fea(self, inp: torchfea.FEA_INP) -> FEAController:
143
+ """
144
+ Create an FEAController instance from the given FEA_INP file and add load interfaces
145
+ Args:
146
+ inp (torchfea.FEA_INP): The FEA input file.
147
+ Returns:
148
+ FEAController: The created FEAController instance with load interfaces added.
149
+ """
150
+
151
+ default_device = torch.tensor(0.).device
152
+ default_dtype = torch.tensor(0.).dtype
153
+
154
+ # get the FEA model
155
+ nodes = inp.part['final_model'].nodes[:, 1:]
156
+ part = torchfea.Part(torch.from_numpy(nodes).to(default_device).to(default_dtype))
157
+ for surface_name, surface in inp.part['final_model'].surfaces.items():
158
+ sf_now = []
159
+ for sf in surface:
160
+ sf_now.append((sf[0], sf[1]))
161
+ part.add_surface_set(surface_name, sf_now)
162
+
163
+ # define the set of nodes
164
+ for set_name, node_indices in inp.part['final_model'].sets_nodes.items():
165
+ part.set_nodes[set_name] = np.unique(np.array(list(node_indices)))
166
+
167
+ index_bottom = np.where(np.abs(nodes[:, 2]-0) < 1e-3)[0]
168
+ part.set_nodes['surface_0_Bottom'] = index_bottom
169
+ index_head = np.where(np.abs(nodes[:, 2]-np.max(nodes[:, 2])) < 1e-3)[0]
170
+ part.set_nodes['surface_0_Head'] = index_head
171
+
172
+ elems = inp.part['final_model'].elems['C3D4'][:, 1:]
173
+ elems_index = inp.part['final_model'].elems['C3D4'][:, 0]
174
+ element = torchfea.elements.initialize_element(element_type='C3D4',
175
+ elems_index=torch.from_numpy(elems_index).to(torch.get_default_device()),
176
+ elems=torch.from_numpy(elems).to(torch.get_default_device()),
177
+ part=part)
178
+
179
+ part.add_element(element)
180
+
181
+ assembly = torchfea.Assembly()
182
+ assembly.add_part(part=part, name='final_model')
183
+ assembly.add_instance(instance=torchfea.Instance(part), name='final_model')
184
+
185
+ fe = torchfea.FEAController()
186
+ fe.assembly = assembly
187
+ fe.solver = torchfea.solver.StaticImplicitSolver(tol_error=1e-6)
188
+
189
+ # Add fea features
190
+ for name, interface in self.feainterfaces.items():
191
+ interface.modify_fea(fe, name)
192
+
193
+ return fe
194
+
195
+
196
+ def process_fea(self, fe: FEAController, step_index: int) -> None:
197
+ """
198
+ Process the FEA controller to update load-related information.
199
+
200
+ Args:
201
+ fe (FEAController): The FEA controller instance.
202
+ step_index (int): The index of the load step.
203
+ """
204
+ load_step_now = self.fea_steps_params[step_index]
205
+ for name, load_interface in self.feainterfaces.items():
206
+ load_interface._values = load_step_now[name]
207
+ load_interface.apply_fea_value(fe, name)
208
+
209
+ def get_parameters(self) -> list[torch.Tensor]:
210
+ """
211
+ Get the parameters.
212
+
213
+ Returns:
214
+ list[torch.Tensor]: the parameters.
215
+ """
216
+ params = []
217
+ for load_step in self.fea_steps_params:
218
+ for params_now in load_step.values():
219
+ params.append(torch.tensor(params_now))
220
+ return params
221
+
222
+ def set_parameters(self, xlist: list[torch.Tensor]) -> None:
223
+ """
224
+ Set the parameters.
225
+
226
+ Args:
227
+ xlist (list[torch.Tensor]): The new parameters.
228
+ """
229
+ ind_now = 0
230
+ for load_step in self.fea_steps_params:
231
+ for key in load_step.keys():
232
+ change_slice = xlist[ind_now]
233
+ load_step[key] = change_slice.detach().cpu().tolist()
234
+ ind_now += 1
235
+
236
+ def get_variables(self) -> torch.Tensor:
237
+ """
238
+ Get the pressure variables.
239
+
240
+ Returns:
241
+ torch.Tensor: The pressure variables.
242
+ """
243
+ xlist = self.get_parameters()
244
+ x_flatten = torch.cat([torch.randn_like(xlist[i].flatten())*1e-6 for i in range(len(xlist))])
245
+ return x_flatten
246
+
247
+ def update_variables(self, x_change: torch.Tensor) -> None:
248
+ """
249
+ Update the pressure variables.
250
+
251
+ Args:
252
+ x_change (torch.Tensor): The change in pressure variables.
253
+ """
254
+ ind_now = 0
255
+
256
+ # Update pressure variables
257
+ for load_step in self.fea_steps_params:
258
+ for key in load_step.keys():
259
+ num_vars = len(load_step[key])
260
+ change_slice = x_change[ind_now:ind_now + num_vars]
261
+ current_params = torch.tensor(load_step[key])
262
+ updated_params = current_params + change_slice
263
+ load_step[key] = updated_params.detach().cpu().tolist()
264
+ ind_now += num_vars
@@ -0,0 +1,3 @@
1
+
2
+ from .geometryparams import GeometryParams
3
+ from .geometryinterfaces import basesurfaceinterface, bspsurfaceinterface
@@ -0,0 +1 @@
1
+ from . import basesurfaceinterface, bspsurfaceinterface