morphopt 3.2.1__tar.gz → 3.2.2__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.
Files changed (116) hide show
  1. {morphopt-3.2.1 → morphopt-3.2.2}/PKG-INFO +1 -1
  2. {morphopt-3.2.1 → morphopt-3.2.2}/README.md +0 -0
  3. {morphopt-3.2.1 → morphopt-3.2.2}/pyproject.toml +1 -1
  4. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/__init__.py +11 -1
  5. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/codesign/__init__.py +6 -4
  6. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/codesign/constraints.py +27 -2
  7. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/codesign/feaparams.py +9 -4
  8. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/codesign/geometry.py +9 -6
  9. morphopt-3.2.2/src/morphopt/optcore/__init__.py +8 -0
  10. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/baseobject.py +0 -0
  11. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/controller.py +0 -0
  12. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/history.py +0 -0
  13. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/__init__.py +1 -1
  14. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/baseparam.py +0 -0
  15. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feainterface/__init__.py +0 -0
  16. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feainterface/basefeainterface.py +0 -0
  17. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feainterface/bodyforceinterface.py +0 -0
  18. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feainterface/boundaryconditioninterface.py +0 -0
  19. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feainterface/contactinterface.py +0 -0
  20. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feainterface/coupleinterface.py +0 -0
  21. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feainterface/pointinterface.py +0 -0
  22. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feainterface/pressureinterface.py +0 -0
  23. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feainterface/referencepointinterface.py +0 -0
  24. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feainterface/springinterface.py +0 -0
  25. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/feaparams.py +0 -0
  26. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/geometry.py +0 -0
  27. morphopt-3.2.2/src/morphopt/optcore/modelparams/materialinterface/__init__.py +11 -0
  28. morphopt-3.2.2/src/morphopt/optcore/modelparams/materialinterface/basematerialinterface.py +69 -0
  29. morphopt-3.2.2/src/morphopt/optcore/modelparams/materialinterface/homogeneousmaterial.py +21 -0
  30. morphopt-3.2.2/src/morphopt/optcore/modelparams/materialinterface/materialmodels.py +111 -0
  31. morphopt-3.2.2/src/morphopt/optcore/modelparams/materials.py +175 -0
  32. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/modelparams/params.py +5 -7
  33. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/objfunc.py +0 -0
  34. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/solver.py +0 -0
  35. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/optcore/updaters.py +0 -0
  36. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/__init__.py +3 -1
  37. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/geometryinterfaces/__init__.py +0 -0
  38. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/geometryparams.py +32 -18
  39. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/objectivefuncs/__init__.py +0 -0
  40. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/objectivefuncs/basefuncs.py +0 -0
  41. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/objectivefuncs/boundarys.py +0 -0
  42. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/objectivefuncs/surfacefairness.py +0 -0
  43. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/objectivefuncs/volumemaximization.py +0 -0
  44. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/objfunc.py +0 -0
  45. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/update_geometry.py +0 -0
  46. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/simp/__init__.py +4 -1
  47. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/simp/objectivefuncs/__init__.py +0 -0
  48. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/simp/objectivefuncs/basefuncs.py +0 -0
  49. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/simp/objectivefuncs/boundarys.py +0 -0
  50. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/simp/objectivefuncs/densityfield.py +0 -0
  51. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/simp/objectivefuncs/sensitivity.py +0 -0
  52. morphopt-3.2.2/src/morphopt/simp/objectivefuncs/volfrac.py +87 -0
  53. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/simp/simpmaterial.py +203 -151
  54. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/simp/solver.py +0 -0
  55. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/simp/update_material.py +36 -25
  56. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/taskoptmization.py +0 -0
  57. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/codegen/generator.py +139 -51
  58. morphopt-3.2.2/src/morphopt/ui/model/__init__.py +20 -0
  59. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/model/problem.py +123 -22
  60. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/model/schemas.py +87 -41
  61. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/schemes/base.py +23 -3
  62. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/schemes/codesign.py +23 -11
  63. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/schemes/shapeopt.py +6 -2
  64. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/schemes/simp.py +11 -6
  65. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/editor.py +30 -4
  66. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/model_tree.py +86 -6
  67. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/values.py +1 -0
  68. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/viewer.py +1 -2
  69. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/workbench.py +12 -8
  70. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/utils/__init__.py +0 -0
  71. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/utils/gradient_check.py +0 -0
  72. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/utils/history_read.py +0 -0
  73. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt.egg-info/PKG-INFO +1 -1
  74. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt.egg-info/SOURCES.txt +4 -1
  75. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt.egg-info/dependency_links.txt +0 -0
  76. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt.egg-info/requires.txt +0 -0
  77. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt.egg-info/top_level.txt +0 -0
  78. {morphopt-3.2.1 → morphopt-3.2.2}/tests/test_fixedGeometry.py +0 -0
  79. {morphopt-3.2.1 → morphopt-3.2.2}/tests/test_path.py +0 -0
  80. morphopt-3.2.1/src/morphopt/codesign/material.py +0 -53
  81. morphopt-3.2.1/src/morphopt/optcore/__init__.py +0 -4
  82. morphopt-3.2.1/src/morphopt/optcore/modelparams/materials.py +0 -119
  83. morphopt-3.2.1/src/morphopt/simp/objectivefuncs/volfrac.py +0 -47
  84. morphopt-3.2.1/src/morphopt/ui/model/__init__.py +0 -16
  85. {morphopt-3.2.1 → morphopt-3.2.2}/setup.cfg +0 -0
  86. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/codesign/params.py +0 -0
  87. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/opt_runner.py +0 -0
  88. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/geometryinterfaces/basesurfaceinterface.py +0 -0
  89. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/geometryinterfaces/bspsurfaceinterface.py +0 -0
  90. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/geometryinterfaces/cpgeosurfaceinterface.py +0 -0
  91. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/objectivefuncs/distancesurface.py +0 -0
  92. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/shapeopt/objectivefuncs/shapederivative.py +0 -0
  93. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/__init__.py +0 -0
  94. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/__main__.py +0 -0
  95. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/app.py +0 -0
  96. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/codegen/__init__.py +0 -0
  97. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/i18n.py +0 -0
  98. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/launcher.py +0 -0
  99. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/mainwindow.py +0 -0
  100. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/model/loaders.py +0 -0
  101. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/observe_panel.py +0 -0
  102. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/schemes/__init__.py +0 -0
  103. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/schemes/snippets.py +0 -0
  104. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/__init__.py +0 -0
  105. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/code_completion.py +0 -0
  106. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/codeeditor.py +0 -0
  107. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/objective_editor.py +0 -0
  108. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/observation_pages.py +0 -0
  109. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/param_form.py +0 -0
  110. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/solver_editor.py +0 -0
  111. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/stepmatrix.py +0 -0
  112. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/template_insert_dialog.py +0 -0
  113. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/torchfea_model_editor.py +0 -0
  114. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt/ui/widgets/updater_editor.py +0 -0
  115. {morphopt-3.2.1 → morphopt-3.2.2}/src/morphopt.egg-info/entry_points.txt +0 -0
  116. {morphopt-3.2.1 → morphopt-3.2.2}/tests/test_ui.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: morphopt
3
- Version: 3.2.1
3
+ Version: 3.2.2
4
4
  Summary: A morphing optimization framework using PyTorch and Abaqus.
5
5
  Requires-Python: >=3.12
6
6
  Description-Content-Type: text/markdown
File without changes
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "morphopt"
3
- version = "3.2.1"
3
+ version = "3.2.2"
4
4
  description = "A morphing optimization framework using PyTorch and Abaqus."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -2,6 +2,13 @@
2
2
  A differentiable structural optimization framework that eliminates manual sensitivity derivation by fusing the adjoint method with automatic differentiation (AD). The sensitivity corresponds to the virtual work of residual force derivatives on the adjoint displacement field, computed via a single backpropagation through the residual graph. MorphOpt provides a unified interface for geometry, load, and material definition, calls torchfea for GPU-accelerated differentiable nonlinear FEA and adjoint-AD sensitivity, and employs a trust-region optimizer with L-BFGS for design updates. Validated on SIMP topology optimization with B-spline density fields and pneumatic soft robot shape optimization with deformation-dependent follower loads.
3
3
  """
4
4
 
5
+ # Torch and TorchFEA use GNU OpenMP in this environment. Set MKL's matching
6
+ # threading layer before importing any module that can load NumPy or Torch.
7
+ import os as __os
8
+ import sys as __sys
9
+
10
+ if __sys.platform.startswith("linux"):
11
+ __os.environ["MKL_THREADING_LAYER"] = "GNU"
5
12
 
6
13
  # region: Logging Configuration
7
14
  import logging as __logging
@@ -57,7 +64,10 @@ def enable_logging(level=__logging.INFO, log_file=None, file_log_level=__logging
57
64
 
58
65
  # region optcore imports
59
66
  from .optcore.controller import Controller
60
- from .optcore.modelparams import FEAParams, FixedGeometryINP, FixedGeometryTorchFEA, FixedGeometry, HomogeneousMaterial, Params
67
+ from .optcore.modelparams import (
68
+ FEAParams, FixedGeometryINP, FixedGeometryTorchFEA, FixedGeometry,
69
+ MaterialsParams, Params,
70
+ )
61
71
  from .optcore.solver import Solver
62
72
  from .optcore.modelparams import Params
63
73
  from .optcore.updaters import Updaters
@@ -1,13 +1,15 @@
1
- from .material import CodesignMaterials
2
1
  from .geometry import CodesignGeometry
3
2
  from .constraints import InwardCurvatureRadius, OffsetSurfaceMinThickness
4
3
  from .feaparams import CodesignFEAParams
5
4
  from .params import Params
6
- from ..optcore import Solver, Updaters
5
+ from ..optcore import (
6
+ MaterialsParams, Solver, Updaters,
7
+ )
7
8
  from ..shapeopt import GeometryParams, UpdaterGeometries, ObjectiveFunction
8
9
  from ..simp import UpdaterMaterials
10
+ from ..simp import SIMP_BSPFieldMaterials
9
11
 
10
- def plot_geometry_and_materials(geometry: CodesignGeometry, materials: CodesignMaterials):
12
+ def plot_geometry_and_materials(geometry: CodesignGeometry, materials: MaterialsParams):
11
13
  import pyvista as pv
12
14
  plotter = pv.Plotter(window_size=(1400, 900))
13
15
  plotter.set_background('white')
@@ -15,4 +17,4 @@ def plot_geometry_and_materials(geometry: CodesignGeometry, materials: CodesignM
15
17
  plotter = materials.plot(plotter=plotter)
16
18
  geometry.plot(plotter=plotter, opacity=[0.0, 1.0])
17
19
 
18
- plotter.show()
20
+ plotter.show()
@@ -49,17 +49,28 @@ class InwardCurvatureRadius(BaseConstraints):
49
49
  super().__init__()
50
50
 
51
51
  self.geometry = geometry
52
+ """Stores the geometry used by InwardCurvatureRadius."""
52
53
  self.surface_start = int(surface_start)
54
+ """Stores the surface start used by InwardCurvatureRadius."""
53
55
  self.surface_ids = None if surface_ids is None else [int(i) for i in surface_ids]
56
+ """Stores the surface ids used by InwardCurvatureRadius."""
54
57
 
55
58
  self.margin = margin
59
+ """Stores the margin used by InwardCurvatureRadius."""
56
60
  self.margin_ratio = float(margin_ratio)
61
+ """Stores the margin ratio used by InwardCurvatureRadius."""
57
62
  self.barrier_thre_ratio = float(barrier_thre_ratio)
63
+ """Stores the barrier thre ratio used by InwardCurvatureRadius."""
58
64
  self.barrier_ratio = float(barrier_ratio)
65
+ """Stores the barrier ratio used by InwardCurvatureRadius."""
59
66
  self.p = int(p)
67
+ """Stores the p used by InwardCurvatureRadius."""
60
68
  self.penalty_scale = float(penalty_scale)
69
+ """Stores the penalty scale used by InwardCurvatureRadius."""
61
70
  self.hard_violation_beta = float(hard_violation_beta)
71
+ """Stores the hard violation beta used by InwardCurvatureRadius."""
62
72
  self.normal_sign = 1.0 if normal_sign >= 0 else -1.0
73
+ """Stores the normal sign used by InwardCurvatureRadius."""
63
74
 
64
75
  @staticmethod
65
76
  def _principal_curvatures(rdu: torch.Tensor, rdu2: torch.Tensor, eps: float = 1e-12) -> tuple[torch.Tensor, torch.Tensor]:
@@ -119,7 +130,6 @@ class InwardCurvatureRadius(BaseConstraints):
119
130
 
120
131
  return loss
121
132
 
122
-
123
133
  class OffsetSurfaceMinThickness(BaseConstraints):
124
134
  """
125
135
  Enforce a minimum distance on the offset surface to reduce self-intersection risk.
@@ -148,23 +158,39 @@ class OffsetSurfaceMinThickness(BaseConstraints):
148
158
  super().__init__()
149
159
 
150
160
  self.geometry = geometry
161
+ """Stores the geometry used by OffsetSurfaceMinThickness."""
151
162
  self.surface_start = int(surface_start)
163
+ """Stores the surface start used by OffsetSurfaceMinThickness."""
152
164
  self.surface_ids = None if surface_ids is None else [int(i) for i in surface_ids]
165
+ """Stores the surface ids used by OffsetSurfaceMinThickness."""
153
166
 
154
167
  self.min_distance = min_distance
168
+ """Stores the min distance used by OffsetSurfaceMinThickness."""
155
169
  self.search_ratio = float(search_ratio)
170
+ """Stores the search ratio used by OffsetSurfaceMinThickness."""
156
171
  self.barrier_thre_ratio = float(barrier_thre_ratio)
172
+ """Stores the barrier thre ratio used by OffsetSurfaceMinThickness."""
157
173
  self.barrier_ratio = float(barrier_ratio)
174
+ """Stores the barrier ratio used by OffsetSurfaceMinThickness."""
158
175
  self.p = int(p)
176
+ """Stores the p used by OffsetSurfaceMinThickness."""
159
177
  self.penalty_scale = float(penalty_scale)
178
+ """Stores the penalty scale used by OffsetSurfaceMinThickness."""
160
179
  self.hard_violation_beta = float(hard_violation_beta)
180
+ """Stores the hard violation beta used by OffsetSurfaceMinThickness."""
161
181
  self.normal_sign = 1.0 if normal_sign >= 0 else -1.0
182
+ """Stores the normal sign used by OffsetSurfaceMinThickness."""
162
183
  self.normal_opposition_thre = float(normal_opposition_thre)
184
+ """Stores the normal opposition thre used by OffsetSurfaceMinThickness."""
163
185
  self.normal_min = float(normal_min)
186
+ """Stores the normal min used by OffsetSurfaceMinThickness."""
164
187
  self.normal_max = float(normal_max)
188
+ """Stores the normal max used by OffsetSurfaceMinThickness."""
165
189
 
166
190
  self._neighbor_pairs: dict[int, torch.Tensor] = {}
191
+ """Stores the neighbor pairs used by OffsetSurfaceMinThickness."""
167
192
  self._neighbor_mindist: dict[int, torch.Tensor] = {}
193
+ """Stores the neighbor mindist used by OffsetSurfaceMinThickness."""
168
194
 
169
195
  def _selected_surface_ids(self, n_surface: int) -> list[int]:
170
196
  if self.surface_ids is None:
@@ -265,4 +291,3 @@ class OffsetSurfaceMinThickness(BaseConstraints):
265
291
  loss = loss + (penalty_strong * scaler_n0[indexl] * scaler_n1[indexl]).sum()
266
292
 
267
293
  return loss
268
-
@@ -4,6 +4,7 @@ import torch
4
4
  import numpy as np
5
5
 
6
6
  import torchfea
7
+ import morphopt
7
8
  from .. import FEAParams
8
9
  import bspmap
9
10
 
@@ -15,7 +16,11 @@ class CodesignFEAParams(FEAParams):
15
16
 
16
17
  def create_fea(self, assembly: torchfea.Assembly) -> torchfea.FEAController:
17
18
  fe = super().create_fea(assembly=assembly)
18
- fe_part = fe.assembly.get_part('final_model')
19
+ geometry = getattr(getattr(morphopt, "controller", None), "params", None)
20
+ geometry = getattr(geometry, "geometry", None)
21
+ part_name = getattr(geometry, "part_name", "final_model")
22
+ instance_name = getattr(geometry, "instance_name", "final_model")
23
+ fe_part = fe.assembly.get_part(part_name)
19
24
 
20
25
  if 'C3D6' in fe_part.elems:
21
26
  element_shell = fe_part.elems['C3D6']
@@ -40,10 +45,10 @@ class CodesignFEAParams(FEAParams):
40
45
  )
41
46
  surfcenter = surfnodes.mean(dim=1)
42
47
 
43
- fe.assembly.get_instance('final_model').exterior_surface = 'surface_1_offset'
48
+ fe.assembly.get_instance(instance_name).exterior_surface = 'surface_1_offset'
44
49
 
45
- mesh_1all = fe.assembly.get_instance('final_model').get_mesh(surf_name='surface_1_All')
46
- mesh_1offset = fe.assembly.get_instance('final_model').get_mesh(surf_name='surface_1_offset')
50
+ mesh_1all = fe.assembly.get_instance(instance_name).get_mesh(surf_name='surface_1_All')
51
+ mesh_1offset = fe.assembly.get_instance(instance_name).get_mesh(surf_name='surface_1_offset')
47
52
 
48
53
  import morphopt
49
54
  normal_cpgeo = morphopt.controller.params.geometry.surface_list[1].get_normals(torch.from_numpy(morphopt.controller.params.geometry.surface_list[1].surf_node_uv).to(torch.get_default_device()))
@@ -6,10 +6,6 @@ import torchfea
6
6
 
7
7
  class CodesignGeometry(GeometryParams):
8
8
 
9
-
10
-
11
-
12
-
13
9
  def __init__(self,
14
10
  fea_seed_size: float,
15
11
  mesh_order: int = 1,
@@ -50,12 +46,19 @@ class CodesignGeometry(GeometryParams):
50
46
  """Element-id offset for the shell block (0-based)."""
51
47
 
52
48
  self._reinit_opt_steps: int = 100
49
+ """Stores the reinit opt steps used by CodesignGeometry."""
53
50
  self._reinit_opt_lr: float = 5e-3
51
+ """Stores the reinit opt lr used by CodesignGeometry."""
54
52
  self._reinit_opt_curvature_weight: float = 1e2
53
+ """Stores the reinit opt curvature weight used by CodesignGeometry."""
55
54
  self._reinit_opt_shape_weight: float = 1e2
55
+ """Stores the reinit opt shape weight used by CodesignGeometry."""
56
56
  self._reinit_opt_curvature_margin_ratio: float = 0.25
57
+ """Stores the reinit opt curvature margin ratio used by CodesignGeometry."""
57
58
  self._reinit_opt_inward_sign: float = 1.0
59
+ """Stores the reinit opt inward sign used by CodesignGeometry."""
58
60
  self._reinit_opt_accept_only_improve: bool = True
61
+ """Stores the reinit opt accept only improve used by CodesignGeometry."""
59
62
 
60
63
  # def reinitialize(self, iteration):
61
64
  # super().reinitialize(iteration)
@@ -334,7 +337,7 @@ class CodesignGeometry(GeometryParams):
334
337
  if len(self._node_idx) == 0 or self._tri_local is None:
335
338
  return
336
339
 
337
- part = assembly.get_part('final_model')
340
+ part = assembly.get_part(self.part_name)
338
341
 
339
342
  nodes = part.nodes.clone()
340
343
  base_ids_t = torch.as_tensor(self._node_idx[0], dtype=torch.long, device=nodes.device)
@@ -356,4 +359,4 @@ class CodesignGeometry(GeometryParams):
356
359
 
357
360
  def plot(self, plotter=None, opacity = None, meshes=None):
358
361
  opacity = [0.0 if i == 0 else 1.0 for i in range(self.num_surface)]
359
- return super().plot(plotter, opacity, meshes)
362
+ return super().plot(plotter, opacity, meshes)
@@ -0,0 +1,8 @@
1
+ from .modelparams import (
2
+ Params, BaseGeometry, FEAParams,
3
+ MaterialsParams, BaseParams,
4
+ FixedGeometryINP, FixedGeometryTorchFEA, FixedGeometry,
5
+ )
6
+ from .updaters import BaseUpdater, Updaters
7
+ from .solver import Solver
8
+ from .objfunc import ObjectiveFunction
@@ -1,5 +1,5 @@
1
1
  from .geometry import FixedGeometryINP, FixedGeometryTorchFEA, FixedGeometry, BaseGeometry
2
2
  from .feaparams import FEAParams
3
- from .materials import HomogeneousMaterial, BaseMaterials
3
+ from .materials import MaterialsParams
4
4
  from .params import Params
5
5
  from .baseparam import BaseParams
@@ -0,0 +1,11 @@
1
+ """Material assignment interfaces."""
2
+
3
+ from .basematerialinterface import BaseMaterialInterface
4
+ from .homogeneousmaterial import HomogeneousMaterial
5
+ from .materialmodels import MaterialModels
6
+
7
+ __all__ = [
8
+ "BaseMaterialInterface",
9
+ "HomogeneousMaterial",
10
+ "MaterialModels",
11
+ ]
@@ -0,0 +1,69 @@
1
+ """Base class for material assignments to TorchFEA parts."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import torch
6
+ import torchfea
7
+
8
+ from ..baseparam import BaseParams
9
+ from .materialmodels import MaterialModels
10
+
11
+
12
+ class BaseMaterialInterface(BaseParams):
13
+ """Assign one material definition to elements in one Part.
14
+
15
+ ``elementname`` may be empty. In that case the interface is applied to
16
+ every element family in ``part_name``.
17
+ """
18
+
19
+ from .materialmodels import MaterialModels as materialmodels
20
+
21
+ def __init__(
22
+ self,
23
+ part_name: str,
24
+ material_parameters: MaterialModels.MaterialParameters,
25
+ elementname: str = "",
26
+ density: float = 0.0,
27
+ ) -> None:
28
+ super().__init__()
29
+ self.part_name = str(part_name or "").strip()
30
+ if not self.part_name:
31
+ raise ValueError("part_name cannot be empty.")
32
+ self.elementname = str(elementname or "").strip()
33
+ self.material_parameters: MaterialModels.MaterialParameters = material_parameters
34
+ self._density: float = float(density)
35
+ self._name: str = ""
36
+
37
+ @property
38
+ def density(self) -> float:
39
+ """Return the mass density assigned to the target elements."""
40
+ return self._density
41
+
42
+ @density.setter
43
+ def density(self, value: float) -> None:
44
+ """Set the mass density assigned to the target elements."""
45
+ self._density = float(value)
46
+
47
+ def target_elements(
48
+ self,
49
+ assembly: torchfea.Assembly,
50
+ ) -> list[tuple[str, torchfea.elements.Element_3D]]:
51
+ """Return the selected element families from the target Part."""
52
+ part = assembly.get_part(self.part_name)
53
+ if self.elementname:
54
+ if self.elementname not in part.elems:
55
+ raise KeyError(
56
+ f"Element {self.elementname!r} does not exist on Part "
57
+ f"{self.part_name!r}.")
58
+ return [(self.elementname, part.elems[self.elementname])]
59
+ if not part.elems:
60
+ raise ValueError(f"Part {self.part_name!r} contains no elements.")
61
+ return list(part.elems.items())
62
+
63
+ def set_materials(self, fe: torchfea.FEAController) -> None:
64
+ """Assign this interface to its target elements."""
65
+ raise NotImplementedError
66
+
67
+ def get_design_values(self) -> torch.Tensor:
68
+ """Return live design values for a designable material interface."""
69
+ return torch.zeros(0)
@@ -0,0 +1,21 @@
1
+ """Uniform material assignment interface."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import torchfea
6
+
7
+ from .basematerialinterface import BaseMaterialInterface
8
+ from .materialmodels import MaterialModels
9
+
10
+
11
+ class HomogeneousMaterial(BaseMaterialInterface):
12
+ """Assign one uniform TorchFEA material to a Part."""
13
+
14
+ def set_materials(self, fe: torchfea.FEAController) -> None:
15
+ """Assign the uniform material and density to target elements."""
16
+ for _name, elements in self.target_elements(fe.assembly):
17
+ elements.delete_material()
18
+ elements.set_materials(MaterialModels.create_material(
19
+ material_parameters=self.material_parameters,
20
+ ))
21
+ elements.density = self.density
@@ -0,0 +1,111 @@
1
+ """TorchFEA material models exposed by :class:`MaterialsParams`."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, fields
6
+ from typing import ClassVar
7
+
8
+ import torchfea
9
+
10
+
11
+ class MaterialModels:
12
+ """Material parameter types and their TorchFEA material classes."""
13
+
14
+ @dataclass(frozen=True)
15
+ class MaterialParameters:
16
+ """Base type for all material parameter objects."""
17
+
18
+ material_class: ClassVar[type[torchfea.materials.Materials_Base]]
19
+
20
+ @dataclass(frozen=True)
21
+ class LinearElasticParams(MaterialParameters):
22
+ """Parameters for ``torchfea.materials.LinearElastic``."""
23
+
24
+ E: float
25
+ nu: float
26
+ material_class: ClassVar[type[torchfea.materials.Materials_Base]] = \
27
+ torchfea.materials.LinearElastic
28
+
29
+ @dataclass(frozen=True)
30
+ class NeoHookeanParams(MaterialParameters):
31
+ """Parameters for ``torchfea.materials.NeoHookean``."""
32
+
33
+ mu: float
34
+ kappa: float
35
+ material_class: ClassVar[type[torchfea.materials.Materials_Base]] = \
36
+ torchfea.materials.NeoHookean
37
+
38
+ @dataclass(frozen=True)
39
+ class NeoHookeanLnJParams(MaterialParameters):
40
+ """Parameters for ``torchfea.materials.NeoHookeanLnJ``."""
41
+
42
+ mu: float
43
+ kappa: float
44
+ material_class: ClassVar[type[torchfea.materials.Materials_Base]] = \
45
+ torchfea.materials.NeoHookeanLnJ
46
+
47
+ @dataclass(frozen=True)
48
+ class MooneyRivlinParams(MaterialParameters):
49
+ """Parameters for ``torchfea.materials.MooneyRivlin``."""
50
+
51
+ c10: float
52
+ c01: float
53
+ kappa: float
54
+ material_class: ClassVar[type[torchfea.materials.Materials_Base]] = \
55
+ torchfea.materials.MooneyRivlin
56
+
57
+ @dataclass(frozen=True)
58
+ class YeohParams(MaterialParameters):
59
+ """Parameters for ``torchfea.materials.Yeoh``."""
60
+
61
+ c1: float
62
+ c2: float
63
+ c3: float
64
+ kappa: float
65
+ material_class: ClassVar[type[torchfea.materials.Materials_Base]] = \
66
+ torchfea.materials.Yeoh
67
+
68
+ @dataclass(frozen=True)
69
+ class GentParams(MaterialParameters):
70
+ """Parameters for ``torchfea.materials.Gent``."""
71
+
72
+ mu: float
73
+ Jm: float
74
+ kappa: float
75
+ material_class: ClassVar[type[torchfea.materials.Materials_Base]] = \
76
+ torchfea.materials.Gent
77
+
78
+ @dataclass(frozen=True)
79
+ class ArrudaBoyceParams(MaterialParameters):
80
+ """Parameters for ``torchfea.materials.ArrudaBoyce``."""
81
+
82
+ mu: float
83
+ N: float
84
+ kappa: float
85
+ material_class: ClassVar[type[torchfea.materials.Materials_Base]] = \
86
+ torchfea.materials.ArrudaBoyce
87
+
88
+ @dataclass(frozen=True)
89
+ class OgdenParams(MaterialParameters):
90
+ """Parameters for ``torchfea.materials.Ogden``."""
91
+
92
+ mu: float
93
+ alpha: float | list[float]
94
+ kappa: float
95
+ material_class: ClassVar[type[torchfea.materials.Materials_Base]] = \
96
+ torchfea.materials.Ogden
97
+
98
+ @classmethod
99
+ def create_material(
100
+ cls,
101
+ material_parameters: MaterialParameters,
102
+ ) -> torchfea.materials.Materials_Base:
103
+ """Create a TorchFEA material from its typed parameter object."""
104
+ if not isinstance(material_parameters, cls.MaterialParameters):
105
+ raise TypeError(
106
+ "material_parameters must be a MaterialModels parameter object.")
107
+ parameters = {
108
+ field.name: getattr(material_parameters, field.name)
109
+ for field in fields(material_parameters)
110
+ }
111
+ return material_parameters.material_class(**parameters)