Skip to content

Commit 3f44cf5

Browse files
Changed spaceclaim_tess to work in batch mode
1 parent a1d75f7 commit 3f44cf5

File tree

2 files changed

+56
-29
lines changed

2 files changed

+56
-29
lines changed
212 Bytes
Binary file not shown.

examples/ansys/spaceclaim_tess/tesseract_api.py

Lines changed: 56 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import numpy as np
1212
import trimesh
1313
from pydantic import BaseModel, Field
14-
from tesseract_core.runtime import Array, Differentiable, Float32
14+
from tesseract_core.runtime import Array, Float32
1515

1616
# Example spaceclaim .exe and script file Paths
1717
# spaceclaim_exe = "F:\\Ansys installations\\ANSYS Inc\\v241\\scdm\\SpaceClaim.exe"
@@ -25,17 +25,17 @@
2525
class InputSchema(BaseModel):
2626
"""Input schema for bar geometry design and SDF generation."""
2727

28-
differentiable_parameters: Differentiable[
28+
differentiable_parameters: list[
2929
Array[
3030
(None,),
3131
Float32,
3232
]
3333
] = Field(
3434
description=(
3535
"Angular positions around the unit circle for the bar geometry. "
36-
"The shape is (num_bars, 2), where num_bars is the number of bars "
36+
"The shape is (num_bars+1, 2), where num_bars is the number of bars "
3737
"and the second dimension has the start then end location of each bar."
38-
"The final +1 entry represents the two z height coordinates for the cutting plane which combine with "
38+
"The first (+1) entry represents the two z height coordinates for the cutting plane which combine with "
3939
"a third fixed coordinate centered on the grid with z = grid_height / 2"
4040
)
4141
)
@@ -64,10 +64,10 @@ class InputSchema(BaseModel):
6464
"grid (pre z-plane cutting). The second is the beam thickness (mm)."
6565
)
6666
)
67-
68-
static_parameters: list[int] = Field(
69-
description=("List of integers used to construct the geometry. ")
70-
)
67+
"""
68+
static_parameters: list[list[int]] = Field(
69+
description=("List of integers used to construct the geometry.")
70+
)"""
7171

7272
string_parameters: list[str] = Field(
7373
description=(
@@ -90,8 +90,8 @@ class TriangularMesh(BaseModel):
9090
class OutputSchema(BaseModel):
9191
"""Output schema for generated geometry and SDF field."""
9292

93-
mesh: TriangularMesh = Field(
94-
description="Triangular mesh representation of the geometry"
93+
meshes: list[TriangularMesh] = Field(
94+
description="Triangular meshes representing the geometries"
9595
)
9696

9797

@@ -100,14 +100,14 @@ class OutputSchema(BaseModel):
100100
#
101101

102102

103-
def build_geometry(
103+
def build_geometries(
104104
differentiable_parameters: np.ndarray,
105105
non_differentiable_parameters: np.ndarray,
106106
string_parameters: list[str],
107107
) -> list[trimesh.Trimesh]:
108108
"""Build a Spaceclaim geometry from the parameters by modifying template .scscript.
109109
110-
Return a TriangularMesh object.
110+
Return a trimesh object.
111111
"""
112112
spaceclaim_exe = Path(string_parameters[0])
113113
spaceclaim_script = Path(string_parameters[1])
@@ -116,17 +116,20 @@ def build_geometry(
116116
# and instead use the unique run directory created everytime the
117117
# tesseract is run (so there is history).
118118
with TemporaryDirectory() as temp_dir:
119-
prepped_script_path, output_file = _prep_scscript(
119+
prepped_script_path = _prep_scscript(
120120
temp_dir,
121121
spaceclaim_script,
122122
differentiable_parameters,
123123
non_differentiable_parameters,
124124
)
125125
run_spaceclaim(spaceclaim_exe, prepped_script_path)
126126

127-
mesh = trimesh.load(output_file)
127+
meshes = []
128+
for output_stl in sorted(Path(temp_dir).glob("*.stl")):
129+
mesh = trimesh.load(output_stl)
130+
meshes.append(mesh)
128131

129-
return mesh
132+
return meshes
130133

131134

132135
def _prep_scscript(
@@ -142,29 +145,50 @@ def _prep_scscript(
142145
# Define output file name and location
143146
# TODO: Same as before: can we output grid_fin.stl in the tesseract
144147
# unique run directory instead of temp dir to keep history?
145-
output_file = os.path.join(temp_dir, "grid_fin.stl")
148+
output_file = os.path.join(
149+
temp_dir, "grid_fin"
150+
) # .stl ending is included in .scscript
146151
prepped_script_path = os.path.join(temp_dir, os.path.basename(spaceclaim_script))
147152
shutil.copy(spaceclaim_script, prepped_script_path)
148153

149154
# Define dict used to input params to .scscript
155+
# Converts np.float32 to python floats so string substitution is clean
150156
keyvalues = {}
151157
keyvalues["__output__"] = output_file
152-
keyvalues["__params__.z2"] = str(differentiable_parameters[0])
153-
keyvalues["__params__.z3"] = str(differentiable_parameters[1])
158+
keyvalues["__params__.zeds"] = [
159+
[float(geom_params[0]), float(geom_params[1])]
160+
for geom_params in differentiable_parameters
161+
]
154162
keyvalues["__params__.height"] = non_differentiable_parameters[0]
155163
keyvalues["__params__.thickness"] = non_differentiable_parameters[1]
156164

157-
num_of_bars = (len(differentiable_parameters) - 2) // 2
165+
num_of_batches = len(differentiable_parameters) # number of geometries requested
166+
num_of_bars = (
167+
len(differentiable_parameters[0]) - 2
168+
) // 2 # Use firt geometry in batch to test number of beams
158169

159170
assert num_of_bars == 8
160171

161-
for i in range(num_of_bars):
162-
keyvalues[f"__params__.s{i + 1}"] = str(differentiable_parameters[i * 2 + 2])
163-
keyvalues[f"__params__.e{i + 1}"] = str(differentiable_parameters[i * 2 + 3])
172+
batch_starts = []
173+
batch_ends = []
174+
for i in range(num_of_batches):
175+
geom_starts = []
176+
geom_ends = []
177+
for j in range(num_of_bars):
178+
geom_starts.append(float(differentiable_parameters[i][j * 2 + 2]))
179+
geom_ends.append(float(differentiable_parameters[i][j * 2 + 3]))
180+
181+
batch_starts.append(geom_starts)
182+
batch_ends.append(geom_ends)
183+
184+
keyvalues["__params__.starts"] = (
185+
batch_starts # convert to string to ease injection into file text
186+
)
187+
keyvalues["__params__.ends"] = batch_ends
164188

165189
_find_and_replace_keys_in_archive(prepped_script_path, keyvalues)
166190

167-
return [prepped_script_path, output_file]
191+
return prepped_script_path
168192

169193

170194
def _safereplace(filedata: str, key: str, value: str) -> str:
@@ -249,17 +273,20 @@ def run_spaceclaim(spaceclaim_exe: Path, spaceclaim_script: Path) -> None:
249273
def apply(inputs: InputSchema) -> OutputSchema:
250274
"""Create a Spaceclaim geometry based on input parameters.
251275
252-
Returns TraingularMesh obj and exports a .stl.
276+
Returns TraingularMesh objects.
253277
"""
254-
mesh = build_geometry(
278+
trimeshes = build_geometries(
255279
differentiable_parameters=inputs.differentiable_parameters,
256280
non_differentiable_parameters=inputs.non_differentiable_parameters,
257281
string_parameters=inputs.string_parameters,
258282
)
259283

260284
return OutputSchema(
261-
mesh=TriangularMesh(
262-
points=mesh.vertices.astype(np.float32),
263-
faces=mesh.faces.astype(np.int32),
264-
)
285+
meshes=[
286+
TriangularMesh(
287+
points=mesh.vertices.astype(np.float32),
288+
faces=mesh.faces.astype(np.int32),
289+
)
290+
for mesh in trimeshes
291+
]
265292
)

0 commit comments

Comments
 (0)