Skip to content

Commit e183976

Browse files
committed
trying to improve mesher
1 parent 2eea14e commit e183976

File tree

6 files changed

+479
-87
lines changed

6 files changed

+479
-87
lines changed

examples/ansys/Readme.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ tesseract-runtime serve --port <port_number_1> --host 0.0.0.0
3636
Note that we dont build a Tesseract image for SpaceClaim in this example. This is because SpaceClaim cannot be installed in a containerized environment. You can test it using git bash and your specific Spaceclaim.exe Path:
3737

3838
```bash
39-
curl -d '{"inputs":{"differentiable_bar_parameters": [[0, 3.14], [0.39, 3.53], [0.79, 3.93], [1.18, 4.32], [1.57, 4.71], [1.96, 5.11], [2.36, 5.50], [2.75, 5.89]], "differentiable_plane_parameters": [200, 600], "non_differentiable_parameters": [800, 100], "string_parameters":["F:\\ANSYS Inc\\v242\\scdm\\SpaceClaim.exe", "geometry_generation.scscript"]}}' -H "Content-Type: application/json" http://172.26.3.35:443/apply
39+
curl -d '{"inputs":{"differentiable_parameters": [200, 600, 0, 3.14, 0.39, 3.53, 0.79, 3.93, 1.18, 4.32, 1.57, 4.71, 1.96, 5.11, 2.36, 5.50, 2.75, 5.89], "non_differentiable_parameters": [800, 100], "string_parameters":["F:\\ANSYS Inc\\v242\\scdm\\SpaceClaim.exe", "geometry_generation.scscript"]}}' -H "Content-Type: application/json" http://0.0.0.0:443/apply
4040
```
4141

4242

0 Bytes
Binary file not shown.

examples/ansys/meshing_tess/tesseract_api.py

Lines changed: 89 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ def vectorized_subdivide_hex_mesh(
116116
hex_cells: jnp.ndarray, # (n_hex, 8)
117117
pts_coords: jnp.ndarray, # (n_points, 3)
118118
mask: jnp.ndarray, # (n_hex,) boolean array indicating which hexes to subdivide
119+
split_x: bool = True,
120+
split_y: bool = True,
121+
split_z: bool = True,
119122
) -> tuple[jnp.ndarray, jnp.ndarray]:
120123
"""Vectorized subdivision of HEX8 mesh.
121124
@@ -138,17 +141,42 @@ def vectorized_subdivide_hex_mesh(
138141
|/____ x
139142
140143
"""
141-
n_hex_new = mask.sum()
142-
n_new_pts = (8 * 8) * n_hex_new # 8 corners per new hex, 8 new hexes per old hex
144+
n_hex_subd = mask.sum()
145+
n_hex_each = (split_x + 1) * (split_y + 1) * (split_z + 1)
146+
n_new_pts = (
147+
8 * n_hex_each
148+
) * n_hex_subd # 8 corners per new hex, 8 new hexes per old hex
149+
n_new_cells = n_hex_each * n_hex_subd
143150

144151
new_pts_coords = jnp.zeros((n_new_pts, 3), dtype=pts_coords.dtype)
145-
new_hex_cells = jnp.zeros((n_hex_new * 8, 8), dtype=hex_cells.dtype)
152+
new_hex_cells = jnp.zeros((n_new_cells, 8), dtype=hex_cells.dtype)
146153

147154
voxel_sizes = jnp.abs(
148155
pts_coords[hex_cells[mask, 6]] - pts_coords[hex_cells[mask, 0]]
149156
)
150157

151158
center_points = jnp.mean(pts_coords[hex_cells[mask]], axis=1) # (n_hex, 3)
159+
160+
cell_offsets = jnp.zeros((1, n_hex_each, 3), dtype=jnp.float32)
161+
index = 0
162+
for ix in range(split_x + 1):
163+
for iy in range(split_y + 1):
164+
for iz in range(split_z + 1):
165+
cell_offsets = cell_offsets.at[0, index].set(
166+
jnp.array(
167+
[
168+
(ix * 0.5 - 0.5) if split_x else 0.0,
169+
(iy * 0.5 - 0.5) if split_y else 0.0,
170+
(iz * 0.5 - 0.5) if split_z else 0.0,
171+
]
172+
).T
173+
)
174+
index += 1
175+
176+
cell_offsets = cell_offsets.repeat(
177+
voxel_sizes.shape[0], axis=0
178+
) * voxel_sizes.reshape((n_hex_subd, 1, 3)).repeat(n_hex_each, axis=1)
179+
152180
offsets = jnp.array(
153181
[
154182
[-0.25, -0.25, -0.25],
@@ -161,20 +189,47 @@ def vectorized_subdivide_hex_mesh(
161189
[-0.25, 0.25, 0.25],
162190
]
163191
).reshape((1, 8, 3)).repeat(voxel_sizes.shape[0], axis=0) * voxel_sizes.reshape(
164-
(n_hex_new, 1, 3)
192+
(n_hex_subd, 1, 3)
165193
).repeat(8, axis=1)
166194

167-
for cell in range(8):
168-
center = center_points + offsets[:, cell]
195+
for cell in range(n_hex_each):
196+
center = center_points + cell_offsets[:, cell]
169197

170198
for corner in range(8):
171199
new_pts_coords = new_pts_coords.at[
172-
jnp.arange(n_hex_new) * 64 + cell * 8 + corner
200+
jnp.arange(n_hex_subd) * 8 * n_hex_each + cell * n_hex_each + corner
173201
].set(center + offsets[:, corner])
174202

175203
new_hex_cells = new_hex_cells.at[
176-
jnp.arange(n_hex_new) * 8 + cell, corner
177-
].set(jnp.arange(n_hex_new) * 64 + cell * 8 + corner)
204+
jnp.arange(n_hex_subd) * n_hex_each + cell, corner
205+
].set(jnp.arange(n_hex_subd) * 8 * n_hex_each + cell * n_hex_each + corner)
206+
207+
# offsets = jnp.array(
208+
# [
209+
# [-0.25, -0.25, -0.25],
210+
# [0.25, -0.25, -0.25],
211+
# [0.25, 0.25, -0.25],
212+
# [-0.25, 0.25, -0.25],
213+
# [-0.25, -0.25, 0.25],
214+
# [0.25, -0.25, 0.25],
215+
# [0.25, 0.25, 0.25],
216+
# [-0.25, 0.25, 0.25],
217+
# ]
218+
# ).reshape((1, 8, 3)).repeat(voxel_sizes.shape[0], axis=0) * voxel_sizes.reshape(
219+
# (n_hex_new, 1, 3)
220+
# ).repeat(8, axis=1)
221+
222+
# for cell in range(8):
223+
# center = center_points + offsets[:, cell]
224+
225+
# for corner in range(8):
226+
# new_pts_coords = new_pts_coords.at[
227+
# jnp.arange(n_hex_new) * 64 + cell * 8 + corner
228+
# ].set(center + offsets[:, corner])
229+
230+
# new_hex_cells = new_hex_cells.at[
231+
# jnp.arange(n_hex_new) * 8 + cell, corner
232+
# ].set(jnp.arange(n_hex_new) * 64 + cell * 8 + corner)
178233

179234
def reindex_and_mask(
180235
coords: jnp.ndarray, cells: jnp.ndarray, keep_mask: jnp.ndarray
@@ -252,19 +307,39 @@ def recursive_subdivide_hex_mesh(
252307
)
253308

254309
for i in range(levels):
255-
voxel_sizes = jnp.max(
256-
jnp.abs(pts_coords[hex_cells[:, 6]] - pts_coords[hex_cells[:, 0]]), axis=1
257-
)
310+
voxel_sizes = jnp.abs(pts_coords[hex_cells[:, 6]] - pts_coords[hex_cells[:, 0]])
311+
258312
voxel_center_points = jnp.mean(pts_coords[hex_cells], axis=1)
259313
sizing_values = interpolator(voxel_center_points)
260-
subdivision_mask = voxel_sizes > sizing_values
314+
subdivision_mask = jnp.max(voxel_sizes, axis=-1) > sizing_values
261315

262316
if not jnp.any(subdivision_mask):
263317
print(f"No more subdivisions needed at level {i}.")
264318
break
265319

320+
split_x = (
321+
voxel_sizes[subdivision_mask, :].max()
322+
/ voxel_sizes[subdivision_mask, 0].mean()
323+
< 2
324+
)
325+
split_y = (
326+
voxel_sizes[subdivision_mask, :].max()
327+
/ voxel_sizes[subdivision_mask, 1].mean()
328+
< 2
329+
)
330+
split_z = (
331+
voxel_sizes[subdivision_mask, :].max()
332+
/ voxel_sizes[subdivision_mask, 2].mean()
333+
< 2
334+
)
335+
266336
pts_coords, hex_cells = vectorized_subdivide_hex_mesh(
267-
hex_cells, pts_coords, subdivision_mask
337+
hex_cells,
338+
pts_coords,
339+
subdivision_mask,
340+
split_x=split_x,
341+
split_y=split_y,
342+
split_z=split_z,
268343
)
269344

270345
pts_coords, hex_cells = remove_duplicate_points(pts_coords, hex_cells)

examples/ansys/optim_bars.ipynb

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@
3333
},
3434
{
3535
"cell_type": "code",
36-
"execution_count": 190,
36+
"execution_count": 2,
3737
"id": "5f5b8544",
3838
"metadata": {},
3939
"outputs": [],
@@ -44,7 +44,7 @@
4444
},
4545
{
4646
"cell_type": "code",
47-
"execution_count": 191,
47+
"execution_count": 3,
4848
"id": "c367fd3b",
4949
"metadata": {},
5050
"outputs": [],
@@ -67,7 +67,7 @@
6767
},
6868
{
6969
"cell_type": "code",
70-
"execution_count": 192,
70+
"execution_count": 4,
7171
"id": "64ebfb56",
7272
"metadata": {},
7373
"outputs": [],
@@ -83,10 +83,25 @@
8383
},
8484
{
8585
"cell_type": "code",
86-
"execution_count": 193,
86+
"execution_count": 5,
8787
"id": "8a407fb1",
8888
"metadata": {},
89-
"outputs": [],
89+
"outputs": [
90+
{
91+
"ename": "FileNotFoundError",
92+
"evalue": "[Errno 2] No such file or directory: '/home/azureuser/localfiles/tesseract-jax/examples/ansys/hot_design_tess'",
93+
"output_type": "error",
94+
"traceback": [
95+
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
96+
"\u001b[31mFileNotFoundError\u001b[39m Traceback (most recent call last)",
97+
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[5]\u001b[39m\u001b[32m, line 3\u001b[39m\n\u001b[32m 1\u001b[39m \u001b[38;5;66;03m# design_tess = Tesseract.from_image(\"design-tube-sdf\")\u001b[39;00m\n\u001b[32m 2\u001b[39m \u001b[38;5;66;03m# design_tess.serve()\u001b[39;00m\n\u001b[32m----> \u001b[39m\u001b[32m3\u001b[39m design_tess = \u001b[43mTesseract\u001b[49m\u001b[43m.\u001b[49m\u001b[43mfrom_tesseract_api\u001b[49m\u001b[43m(\u001b[49m\u001b[33;43m\"\u001b[39;49m\u001b[33;43mhot_design_tess/tesseract_api.py\u001b[39;49m\u001b[33;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\n\u001b[32m 4\u001b[39m bar_3d_tess = Tesseract.from_tesseract_api(\u001b[33m\"\u001b[39m\u001b[33mbars_3d_tess/tesseract_api.py\u001b[39m\u001b[33m\"\u001b[39m)\n",
98+
"\u001b[36mFile \u001b[39m\u001b[32m/anaconda/envs/fem/lib/python3.13/site-packages/tesseract_core/sdk/tesseract.py:188\u001b[39m, in \u001b[36mTesseract.from_tesseract_api\u001b[39m\u001b[34m(cls, tesseract_api, input_path, output_path, output_format)\u001b[39m\n\u001b[32m 185\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(tesseract_api, \u001b[38;5;28mstr\u001b[39m | Path):\n\u001b[32m 186\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mtesseract_core\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mruntime\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mcore\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m load_module_from_path\n\u001b[32m--> \u001b[39m\u001b[32m188\u001b[39m tesseract_api_path = \u001b[43mPath\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtesseract_api\u001b[49m\u001b[43m)\u001b[49m\u001b[43m.\u001b[49m\u001b[43mresolve\u001b[49m\u001b[43m(\u001b[49m\u001b[43mstrict\u001b[49m\u001b[43m=\u001b[49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m\n\u001b[32m 189\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m tesseract_api_path.is_file():\n\u001b[32m 190\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\n\u001b[32m 191\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mTesseract API path \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mtesseract_api_path\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m is not a file.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 192\u001b[39m )\n",
99+
"\u001b[36mFile \u001b[39m\u001b[32m/anaconda/envs/fem/lib/python3.13/pathlib/_local.py:670\u001b[39m, in \u001b[36mPath.resolve\u001b[39m\u001b[34m(self, strict)\u001b[39m\n\u001b[32m 664\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mresolve\u001b[39m(\u001b[38;5;28mself\u001b[39m, strict=\u001b[38;5;28;01mFalse\u001b[39;00m):\n\u001b[32m 665\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"\u001b[39;00m\n\u001b[32m 666\u001b[39m \u001b[33;03m Make the path absolute, resolving all symlinks on the way and also\u001b[39;00m\n\u001b[32m 667\u001b[39m \u001b[33;03m normalizing it.\u001b[39;00m\n\u001b[32m 668\u001b[39m \u001b[33;03m \"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m670\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m.with_segments(\u001b[43mos\u001b[49m\u001b[43m.\u001b[49m\u001b[43mpath\u001b[49m\u001b[43m.\u001b[49m\u001b[43mrealpath\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstrict\u001b[49m\u001b[43m=\u001b[49m\u001b[43mstrict\u001b[49m\u001b[43m)\u001b[49m)\n",
100+
"\u001b[36mFile \u001b[39m\u001b[32m<frozen posixpath>:454\u001b[39m, in \u001b[36mrealpath\u001b[39m\u001b[34m(filename, strict)\u001b[39m\n",
101+
"\u001b[31mFileNotFoundError\u001b[39m: [Errno 2] No such file or directory: '/home/azureuser/localfiles/tesseract-jax/examples/ansys/hot_design_tess'"
102+
]
103+
}
104+
],
90105
"source": [
91106
"# design_tess = Tesseract.from_image(\"design-tube-sdf\")\n",
92107
"# design_tess.serve()\n",
@@ -189,7 +204,7 @@
189204
},
190205
{
191206
"cell_type": "code",
192-
"execution_count": 218,
207+
"execution_count": null,
193208
"id": "760cf3ee",
194209
"metadata": {},
195210
"outputs": [
@@ -265,7 +280,7 @@
265280
},
266281
{
267282
"cell_type": "code",
268-
"execution_count": 219,
283+
"execution_count": null,
269284
"id": "85a4ee0e",
270285
"metadata": {},
271286
"outputs": [
@@ -338,7 +353,7 @@
338353
},
339354
{
340355
"cell_type": "code",
341-
"execution_count": 197,
356+
"execution_count": null,
342357
"id": "7d008a70",
343358
"metadata": {},
344359
"outputs": [],
@@ -376,7 +391,7 @@
376391
},
377392
{
378393
"cell_type": "code",
379-
"execution_count": 198,
394+
"execution_count": null,
380395
"id": "c781713f",
381396
"metadata": {},
382397
"outputs": [],
@@ -416,7 +431,7 @@
416431
},
417432
{
418433
"cell_type": "code",
419-
"execution_count": 199,
434+
"execution_count": null,
420435
"id": "db2b5929",
421436
"metadata": {},
422437
"outputs": [],
@@ -443,7 +458,7 @@
443458
},
444459
{
445460
"cell_type": "code",
446-
"execution_count": 220,
461+
"execution_count": null,
447462
"id": "798defb2",
448463
"metadata": {},
449464
"outputs": [
@@ -490,7 +505,7 @@
490505
},
491506
{
492507
"cell_type": "code",
493-
"execution_count": 244,
508+
"execution_count": null,
494509
"id": "0d271c6c",
495510
"metadata": {},
496511
"outputs": [
@@ -552,15 +567,19 @@
552567
},
553568
{
554569
"cell_type": "code",
555-
"execution_count": 245,
570+
"execution_count": 6,
556571
"id": "44a48a0c",
557572
"metadata": {},
558573
"outputs": [
559574
{
560-
"name": "stdout",
561-
"output_type": "stream",
562-
"text": [
563-
"Mesh points: 1645, Mesh faces: 1184\n"
575+
"ename": "NameError",
576+
"evalue": "name 'Lx' is not defined",
577+
"output_type": "error",
578+
"traceback": [
579+
"\u001b[31m---------------------------------------------------------------------------\u001b[39m",
580+
"\u001b[31mNameError\u001b[39m Traceback (most recent call last)",
581+
"\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[6]\u001b[39m\u001b[32m, line 6\u001b[39m\n\u001b[32m 1\u001b[39m mesher = Tesseract.from_tesseract_api(\u001b[33m\"\u001b[39m\u001b[33mmeshing_tess/tesseract_api.py\u001b[39m\u001b[33m\"\u001b[39m)\n\u001b[32m 3\u001b[39m mesher_out = apply_tesseract(\n\u001b[32m 4\u001b[39m mesher,\n\u001b[32m 5\u001b[39m {\n\u001b[32m----> \u001b[39m\u001b[32m6\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mdomain_size\u001b[39m\u001b[33m\"\u001b[39m: [\u001b[43mLx\u001b[49m, Ly, Lz],\n\u001b[32m 7\u001b[39m \u001b[33m\"\u001b[39m\u001b[33msizing_field\u001b[39m\u001b[33m\"\u001b[39m: sizing, \u001b[38;5;66;03m# jnp.ones_like(sdf) * (Lx / 10),\u001b[39;00m\n\u001b[32m 8\u001b[39m \u001b[38;5;66;03m# \"sizing_field\": jnp.ones_like(sdf) * (Lx / 10),\u001b[39;00m\n\u001b[32m 9\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mfield_values\u001b[39m\u001b[33m\"\u001b[39m: rho,\n\u001b[32m 10\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mmax_subdivision_levels\u001b[39m\u001b[33m\"\u001b[39m: \u001b[32m4\u001b[39m,\n\u001b[32m 11\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mmax_points\u001b[39m\u001b[33m\"\u001b[39m: \u001b[32m5000\u001b[39m,\n\u001b[32m 12\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mmax_cells\u001b[39m\u001b[33m\"\u001b[39m: \u001b[32m5000\u001b[39m,\n\u001b[32m 13\u001b[39m },\n\u001b[32m 14\u001b[39m )\n\u001b[32m 15\u001b[39m \u001b[38;5;28mprint\u001b[39m(\n\u001b[32m 16\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mMesh points: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmesher_out[\u001b[33m'\u001b[39m\u001b[33mmesh\u001b[39m\u001b[33m'\u001b[39m][\u001b[33m'\u001b[39m\u001b[33mn_points\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m, Mesh faces: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mmesher_out[\u001b[33m'\u001b[39m\u001b[33mmesh\u001b[39m\u001b[33m'\u001b[39m][\u001b[33m'\u001b[39m\u001b[33mn_faces\u001b[39m\u001b[33m'\u001b[39m]\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 17\u001b[39m )\n\u001b[32m 18\u001b[39m pts = mesher_out[\u001b[33m\"\u001b[39m\u001b[33mmesh\u001b[39m\u001b[33m\"\u001b[39m][\u001b[33m\"\u001b[39m\u001b[33mpoints\u001b[39m\u001b[33m\"\u001b[39m][: mesher_out[\u001b[33m\"\u001b[39m\u001b[33mmesh\u001b[39m\u001b[33m\"\u001b[39m][\u001b[33m\"\u001b[39m\u001b[33mn_points\u001b[39m\u001b[33m\"\u001b[39m]]\n",
582+
"\u001b[31mNameError\u001b[39m: name 'Lx' is not defined"
564583
]
565584
}
566585
],

0 commit comments

Comments
 (0)