Skip to content

Commit 63fe23d

Browse files
committed
Rough draft of support for imprinted assemblies
1 parent d1f6a8f commit 63fe23d

File tree

2 files changed

+155
-0
lines changed

2 files changed

+155
-0
lines changed

assembly_mesh_plugin/plugin.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,131 @@ def assembly_to_gmsh(self, mesh_path="tagged_mesh.msh"):
182182
gmsh.finalize()
183183

184184

185+
def assembly_to_imprinted_gmsh(self, mesh_path="tagged_mesh.msh"):
186+
"""
187+
Exports an imprinted assembly to capture conformal meshes.
188+
"""
189+
190+
gmsh.initialize()
191+
gmsh.option.setNumber("General.Terminal", 0)
192+
gmsh.model.add("assembly")
193+
194+
# The mesh volume and surface ids should line up with the order of solids and faces in the assembly
195+
vol_id = 1
196+
surface_id = 1
197+
198+
# Tracks multi-surface physical groups
199+
multi_material_groups = {}
200+
surface_groups = {}
201+
202+
# Tracks the solids with tagged faces
203+
tagged_faces = {}
204+
solids_with_tagged_faces = {}
205+
206+
# Imprint the assembly
207+
imprinted_assembly, imprinted_solids_with_orginal_ids = (
208+
cq.occ_impl.assembly.imprint(self)
209+
)
210+
211+
print(imprinted_solids_with_orginal_ids)
212+
for solid, id in imprinted_solids_with_orginal_ids.items():
213+
# Add the current solid to the mesh
214+
# Work-around for a segfault with in-memory passing of OCCT objects
215+
with tempfile.NamedTemporaryFile(suffix=".brep") as temp_file:
216+
solid.exportBrep(temp_file.name)
217+
ps = gmsh.model.occ.importShapes(temp_file.name)
218+
gmsh.model.occ.synchronize()
219+
220+
# Technically, importShapes could import multiple entities/dimensions, so filter those
221+
vol_ents = []
222+
for p in ps:
223+
if p[0] == 3:
224+
vol_ents.append(p[1])
225+
226+
# Set the physical name to be the part name in the assembly for all the solids
227+
ps2 = gmsh.model.addPhysicalGroup(3, vol_ents)
228+
gmsh.model.setPhysicalName(3, ps2, f"{id[0].split('/')[-1]}")
229+
230+
# Get the original assembly part
231+
object_name = id[0].split("/")[-1]
232+
assembly_part = self.objects[object_name]
233+
234+
# Collect any tags from the part
235+
for tag, wp in assembly_part.obj.ctx.tags.items():
236+
tagged_face = wp.faces().all()[0].val()
237+
for face in wp.faces().all():
238+
tagged_faces[face.val()] = tag
239+
240+
# Iterate over the faces of the assembly part
241+
for face in assembly_part.obj.faces():
242+
for tagged_face, tag in tagged_faces.items():
243+
if TopoDS_Shape.IsEqual(face.wrapped, tagged_face.wrapped):
244+
print(f"{vol_id}_{surface_id}", tag)
245+
solids_with_tagged_faces[f"{vol_id}_{surface_id}"] = (
246+
object_name,
247+
tag,
248+
)
249+
250+
surface_id += 1
251+
vol_id += 1
252+
253+
# Reset the volume and surface IDs
254+
vol_id = 1
255+
surface_id = 1
256+
257+
# Step through the imprinted assembly/shape and check for tagged faces
258+
for solid in imprinted_assembly.solids():
259+
for face in solid.faces().Faces():
260+
# Check to see if this face has been tagged
261+
if f"{vol_id}_{surface_id}" in solids_with_tagged_faces.keys():
262+
short_name = solids_with_tagged_faces[f"{vol_id}_{surface_id}"][0]
263+
tag = solids_with_tagged_faces[f"{vol_id}_{surface_id}"][1]
264+
265+
# Find out if this is a multi-material tag
266+
if tag.startswith("~"):
267+
# Set the surface name to be the name of the tag without the ~
268+
group_name = tag.replace("~", "").split("-")[0]
269+
270+
# Add this face to the multi-material group
271+
if group_name in multi_material_groups:
272+
multi_material_groups[group_name].append(surface_id)
273+
else:
274+
multi_material_groups[group_name] = [surface_id]
275+
else:
276+
# We want to track all surfaces that might be in a tag group
277+
cur_tag_name = f"{short_name}_{tag}"
278+
if cur_tag_name in surface_groups:
279+
print("Append: ", cur_tag_name, short_name, surface_id)
280+
surface_groups[cur_tag_name].append(surface_id)
281+
else:
282+
print("New: ", cur_tag_name, short_name, surface_id)
283+
surface_groups[cur_tag_name] = [surface_id]
284+
285+
surface_id += 1
286+
vol_id += 1
287+
288+
# Handle tagged surface groups
289+
for t_name, surf_group in surface_groups.items():
290+
ps = gmsh.model.addPhysicalGroup(2, surf_group)
291+
gmsh.model.setPhysicalName(2, ps, t_name)
292+
293+
# Handle multi-material tags
294+
for group_name, mm_group in multi_material_groups.items():
295+
ps = gmsh.model.addPhysicalGroup(2, mm_group)
296+
gmsh.model.setPhysicalName(2, ps, f"{group_name}")
297+
298+
gmsh.model.occ.synchronize()
299+
300+
gmsh.model.mesh.field.setAsBackgroundMesh(2)
301+
302+
gmsh.model.mesh.generate(3)
303+
gmsh.write(mesh_path)
304+
305+
gmsh.finalize()
306+
307+
185308
# Patch the new assembly functions into CadQuery's importers package
186309
cq.Assembly.assemblyToGmsh = assembly_to_gmsh
187310
cq.Assembly.saveToGmsh = assembly_to_gmsh # Alias name that works better on cq.Assembly
188311
cq.Assembly.getTaggedGmsh = get_tagged_gmsh
312+
cq.Assembly.assemblyToImprintedGmsh = assembly_to_imprinted_gmsh

tests/test_meshes.py

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,34 @@ def test_subshape_assembly():
7979
continue
8080

8181
assert cur_name in ["cube_1_cube_1_top_face"]
82+
83+
84+
def test_imprinted_assembly():
85+
# Create the basic assembly
86+
assy = generate_simple_nested_boxes()
87+
88+
assy.assemblyToImprintedGmsh("tagged_imprinted_mesh.msh")
89+
90+
gmsh.initialize()
91+
92+
gmsh.open("tagged_imprinted_mesh.msh")
93+
94+
# Check the solids for the correct tags
95+
physical_groups = gmsh.model.getPhysicalGroups(3)
96+
for group in physical_groups:
97+
# Get the name for the current volume
98+
cur_name = gmsh.model.getPhysicalName(3, group[1])
99+
100+
assert cur_name in ["shell", "insert"]
101+
102+
# Check the surfaces for the correct tags
103+
physical_groups = gmsh.model.getPhysicalGroups(2)
104+
for group in physical_groups:
105+
# Get the name for this group
106+
cur_name = gmsh.model.getPhysicalName(2, group[1])
107+
108+
# Skip any groups that are not tagged explicitly
109+
if "_surface_" in cur_name:
110+
continue
111+
112+
assert cur_name in ["shell_inner-right", "insert_outer-right", "in_contact"]

0 commit comments

Comments
 (0)