Skip to content

Commit ba7a954

Browse files
Added Spaceclaim tesserat(runtime) files
1 parent 833d349 commit ba7a954

File tree

4 files changed

+171
-0
lines changed

4 files changed

+171
-0
lines changed
1.03 MB
Binary file not shown.
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
# Copyright 2025 Pasteur Labs. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
import os
5+
import shutil
6+
import subprocess
7+
import zipfile
8+
from pathlib import Path, WindowsPath
9+
from tempfile import TemporaryDirectory
10+
11+
from pydantic import BaseModel, Field
12+
13+
# Temporary hardcoded spaceclaim .exe and script files
14+
spaceclaim_exe = "F:\\Ansys installations\\ANSYS Inc\\v241\\scdm\\SpaceClaim.exe"
15+
spaceclaim_script = "geometry_generation.scscript" # Relies on being executed in same directory as tesseract_api.py
16+
17+
"""
18+
Example dict for 8 beam start (s) and end (e) parameters and two z-plane params
19+
20+
keyvalues_test = {"__params__.z2": "200",
21+
"__params__.z3": "600",
22+
"__params__.s1": "0",
23+
"__params__.s2": "1 * (math.pi / 8)",
24+
"__params__.s3": "2 * (math.pi / 8)",
25+
"__params__.s4": "3 * (math.pi / 8)",
26+
"__params__.s5": "4 * (math.pi / 8)",
27+
"__params__.s6": "5 * (math.pi / 8)",
28+
"__params__.s7": "6 * (math.pi / 8)",
29+
"__params__.s8": "7 * (math.pi / 8)",
30+
"__params__.e1": "(0) + math.pi",
31+
"__params__.e2": "(1 * (math.pi / 8)) + math.pi",
32+
"__params__.e3": "(2 * (math.pi / 8)) + math.pi",
33+
"__params__.e4": "(3 * (math.pi / 8)) + math.pi",
34+
"__params__.e5": "(4 * (math.pi / 8)) + math.pi",
35+
"__params__.e6": "(5 * (math.pi / 8)) + math.pi",
36+
"__params__.e7": "(6 * (math.pi / 8)) + math.pi",
37+
"__params__.e8": "(7 * (math.pi / 8)) + math.pi"}
38+
"""
39+
40+
41+
class InputSchema(BaseModel):
42+
grid_parameters: dict = Field(
43+
description="Parameter dictionary defining location of grid beams and Z cutting plane"
44+
)
45+
46+
47+
class OutputSchema(BaseModel):
48+
placeholder_output: str = Field(
49+
description="A placeholder output as this tesseract creates a .stl."
50+
)
51+
52+
53+
def _safereplace(filedata: str, key: str, value: str) -> str:
54+
# ensure double backspace in windows path
55+
if isinstance(value, WindowsPath):
56+
value = str(value)
57+
value = value.replace("\\", "\\\\")
58+
else:
59+
value = str(value)
60+
return filedata.replace(key, value)
61+
62+
63+
def _find_and_replace_keys_in_archive(file: Path, keyvalues: dict) -> None:
64+
# work on the zip in a temporary directory
65+
with TemporaryDirectory() as temp_dir:
66+
# extract zip
67+
with zipfile.ZipFile(file, "r") as zip_ref:
68+
zip_ref.extractall(temp_dir)
69+
70+
# walk through the extracted files/folders
71+
for foldername, _subfolders, filenames in os.walk(temp_dir):
72+
for filename in filenames:
73+
# read in file
74+
filepath = os.path.join(foldername, filename)
75+
try:
76+
with open(filepath) as f:
77+
filedata = f.read()
78+
except Exception:
79+
filedata = None
80+
81+
# find/replace
82+
if filedata:
83+
for key, value in keyvalues.items():
84+
if value is not None:
85+
filedata = _safereplace(filedata, key, value)
86+
87+
# write to file
88+
with open(filepath, "w") as f:
89+
f.write(filedata)
90+
91+
# write out all files back to zip
92+
with zipfile.ZipFile(file, "w") as zip_ref:
93+
for foldername, _subfolders, filenames in os.walk(temp_dir):
94+
for filename in filenames:
95+
filepath = os.path.join(foldername, filename)
96+
zip_ref.write(
97+
filepath,
98+
arcname=os.path.relpath(filepath, start=temp_dir),
99+
)
100+
101+
102+
def run_spaceclaim(spaceclaim_exe: Path, spaceclaim_script: Path):
103+
env = os.environ.copy()
104+
cmd = str(
105+
f'"{spaceclaim_exe}" /UseLicenseMode=True /Welcome=False /Splash=False '
106+
+ f'/RunScript="{spaceclaim_script}" /ExitAfterScript=True /Headless=True'
107+
)
108+
109+
result = subprocess.run(
110+
cmd,
111+
shell=True,
112+
check=False,
113+
capture_output=True,
114+
text=True,
115+
env=env,
116+
)
117+
118+
return result.returncode
119+
120+
121+
#
122+
# Tesseract endpoints
123+
#
124+
125+
126+
def apply(inputs: InputSchema) -> OutputSchema:
127+
"""Create a Spaceclaim geometry based on input parameters and export as a .stl."""
128+
cwd = os.getcwd()
129+
output_file = os.path.join(cwd, "grid_fin.stl")
130+
131+
keyvalues = inputs.grid_parameters.copy()
132+
keyvalues["__output__"] = output_file
133+
134+
with TemporaryDirectory() as temp_dir:
135+
# Copy spaceclaim template script to temp dir
136+
copied_file_path = os.path.join(temp_dir, os.path.basename(spaceclaim_script))
137+
shutil.copy(spaceclaim_script, copied_file_path)
138+
139+
# Update temp spaceclaim script and use to generate .stl
140+
update_script = _find_and_replace_keys_in_archive(copied_file_path, keyvalues)
141+
spaceclaim_result = run_spaceclaim(spaceclaim_exe, copied_file_path)
142+
143+
return OutputSchema(
144+
placeholder_output=f"Subprocess return code: {spaceclaim_result}"
145+
)
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: "spaceclaim"
2+
version: "1.0.0"
3+
description: "Testing wrapping Spaceclaim in a runtime tesseract"
4+
5+
build_config:
6+
# Base image to use for the container, must be Ubuntu or Debian-based
7+
# base_image: "debian:bookworm-slim"
8+
9+
# Platform to build the container for. In general, images can only be executed
10+
# on the platform they were built for.
11+
# target_platform: "native"
12+
13+
# Additional packages to install in the container (via apt-get)
14+
# extra_packages:
15+
# - package_name
16+
17+
# Data to copy into the container, relative to the project root
18+
# package_data:
19+
# - [path/to/source, path/to/destination]
20+
21+
# Additional Dockerfile commands to run during the build process
22+
# custom_build_steps:
23+
# - |
24+
# RUN echo "Hello, World!"
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Add Python requirements like this:
2+
# numpy==1.18.1

0 commit comments

Comments
 (0)