cad-to-dagmc 0.4.0__py3-none-any.whl → 0.5.1__py3-none-any.whl
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.
Potentially problematic release.
This version of cad-to-dagmc might be problematic. Click here for more details.
- _version.py +14 -2
- cad_to_dagmc/__init__.py +1 -4
- cad_to_dagmc/core.py +378 -70
- {cad_to_dagmc-0.4.0.dist-info → cad_to_dagmc-0.5.1.dist-info}/METADATA +34 -28
- cad_to_dagmc-0.5.1.dist-info/RECORD +8 -0
- {cad_to_dagmc-0.4.0.dist-info → cad_to_dagmc-0.5.1.dist-info}/WHEEL +1 -1
- cad_to_dagmc/brep_part_finder.py +0 -37
- cad_to_dagmc/brep_to_h5m.py +0 -118
- cad_to_dagmc/vertices_to_h5m.py +0 -211
- cad_to_dagmc-0.4.0.dist-info/RECORD +0 -11
- {cad_to_dagmc-0.4.0.dist-info → cad_to_dagmc-0.5.1.dist-info}/LICENSE +0 -0
- {cad_to_dagmc-0.4.0.dist-info → cad_to_dagmc-0.5.1.dist-info}/top_level.txt +0 -0
_version.py
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
# file generated by setuptools_scm
|
|
2
2
|
# don't change, don't track in version control
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
TYPE_CHECKING = False
|
|
4
|
+
if TYPE_CHECKING:
|
|
5
|
+
from typing import Tuple, Union
|
|
6
|
+
VERSION_TUPLE = Tuple[Union[int, str], ...]
|
|
7
|
+
else:
|
|
8
|
+
VERSION_TUPLE = object
|
|
9
|
+
|
|
10
|
+
version: str
|
|
11
|
+
__version__: str
|
|
12
|
+
__version_tuple__: VERSION_TUPLE
|
|
13
|
+
version_tuple: VERSION_TUPLE
|
|
14
|
+
|
|
15
|
+
__version__ = version = '0.5.1'
|
|
16
|
+
__version_tuple__ = version_tuple = (0, 5, 1)
|
cad_to_dagmc/__init__.py
CHANGED
cad_to_dagmc/core.py
CHANGED
|
@@ -1,23 +1,375 @@
|
|
|
1
1
|
import typing
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import cadquery as cq
|
|
5
|
+
import gmsh
|
|
6
|
+
import numpy as np
|
|
7
|
+
import OCP
|
|
8
|
+
import trimesh
|
|
2
9
|
from cadquery import importers
|
|
10
|
+
from pymoab import core, types
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def fix_normals(vertices: typing.Sequence, triangles_in_each_volume: typing.Sequence):
|
|
14
|
+
fixed_triangles = []
|
|
15
|
+
for triangles in triangles_in_each_volume:
|
|
16
|
+
fixed_triangles.append(fix_normal(vertices, triangles))
|
|
17
|
+
return fixed_triangles
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def fix_normal(vertices: typing.Sequence, triangles: typing.Sequence):
|
|
21
|
+
mesh = trimesh.Trimesh(vertices=vertices, faces=triangles, process=False)
|
|
22
|
+
|
|
23
|
+
mesh.fix_normals()
|
|
24
|
+
|
|
25
|
+
return mesh.faces
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def define_moab_core_and_tags() -> typing.Tuple[core.Core, dict]:
|
|
29
|
+
"""Creates a MOAB Core instance which can be built up by adding sets of
|
|
30
|
+
triangles to the instance
|
|
31
|
+
|
|
32
|
+
Returns:
|
|
33
|
+
(pymoab Core): A pymoab.core.Core() instance
|
|
34
|
+
(pymoab tag_handle): A pymoab.core.tag_get_handle() instance
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
# create pymoab instance
|
|
38
|
+
moab_core = core.Core()
|
|
39
|
+
|
|
40
|
+
tags = dict()
|
|
41
|
+
|
|
42
|
+
sense_tag_name = "GEOM_SENSE_2"
|
|
43
|
+
sense_tag_size = 2
|
|
44
|
+
tags["surf_sense"] = moab_core.tag_get_handle(
|
|
45
|
+
sense_tag_name,
|
|
46
|
+
sense_tag_size,
|
|
47
|
+
types.MB_TYPE_HANDLE,
|
|
48
|
+
types.MB_TAG_SPARSE,
|
|
49
|
+
create_if_missing=True,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
tags["category"] = moab_core.tag_get_handle(
|
|
53
|
+
types.CATEGORY_TAG_NAME,
|
|
54
|
+
types.CATEGORY_TAG_SIZE,
|
|
55
|
+
types.MB_TYPE_OPAQUE,
|
|
56
|
+
types.MB_TAG_SPARSE,
|
|
57
|
+
create_if_missing=True,
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
tags["name"] = moab_core.tag_get_handle(
|
|
61
|
+
types.NAME_TAG_NAME,
|
|
62
|
+
types.NAME_TAG_SIZE,
|
|
63
|
+
types.MB_TYPE_OPAQUE,
|
|
64
|
+
types.MB_TAG_SPARSE,
|
|
65
|
+
create_if_missing=True,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
tags["geom_dimension"] = moab_core.tag_get_handle(
|
|
69
|
+
types.GEOM_DIMENSION_TAG_NAME,
|
|
70
|
+
1,
|
|
71
|
+
types.MB_TYPE_INTEGER,
|
|
72
|
+
types.MB_TAG_DENSE,
|
|
73
|
+
create_if_missing=True,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Global ID is a default tag, just need the name to retrieve
|
|
77
|
+
tags["global_id"] = moab_core.tag_get_handle(types.GLOBAL_ID_TAG_NAME)
|
|
78
|
+
|
|
79
|
+
return moab_core, tags
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def vertices_to_h5m(
|
|
83
|
+
vertices: typing.Union[
|
|
84
|
+
typing.Iterable[typing.Tuple[float, float, float]],
|
|
85
|
+
typing.Iterable["cadquery.occ_impl.geom.Vector"],
|
|
86
|
+
],
|
|
87
|
+
triangles_by_solid_by_face: typing.Iterable[typing.Iterable[typing.Tuple[int, int, int]]],
|
|
88
|
+
material_tags: typing.Iterable[str],
|
|
89
|
+
h5m_filename="dagmc.h5m",
|
|
90
|
+
):
|
|
91
|
+
"""Converts vertices and triangle sets into a tagged h5m file compatible
|
|
92
|
+
with DAGMC enabled neutronics simulations
|
|
93
|
+
|
|
94
|
+
Args:
|
|
95
|
+
vertices:
|
|
96
|
+
triangles:
|
|
97
|
+
material_tags:
|
|
98
|
+
h5m_filename:
|
|
99
|
+
"""
|
|
100
|
+
|
|
101
|
+
if len(material_tags) != len(triangles_by_solid_by_face):
|
|
102
|
+
msg = f"The number of material_tags provided is {len(material_tags)} and the number of sets of triangles is {len(triangles_by_solid_by_face)}. You must provide one material_tag for every triangle set"
|
|
103
|
+
raise ValueError(msg)
|
|
104
|
+
|
|
105
|
+
# limited attribute checking to see if user passed in a list of CadQuery vectors
|
|
106
|
+
if hasattr(vertices[0], "x") and hasattr(vertices[0], "y") and hasattr(vertices[0], "z"):
|
|
107
|
+
vertices_floats = []
|
|
108
|
+
for vert in vertices:
|
|
109
|
+
vertices_floats.append((vert.x, vert.y, vert.z))
|
|
110
|
+
else:
|
|
111
|
+
vertices_floats = vertices
|
|
112
|
+
|
|
113
|
+
face_ids_with_solid_ids = {}
|
|
114
|
+
for solid_id, triangles_on_each_face in triangles_by_solid_by_face.items():
|
|
115
|
+
for face_id, triangles_on_face in triangles_on_each_face.items():
|
|
116
|
+
if face_id in face_ids_with_solid_ids.keys():
|
|
117
|
+
face_ids_with_solid_ids[face_id].append(solid_id)
|
|
118
|
+
else:
|
|
119
|
+
face_ids_with_solid_ids[face_id] = [solid_id]
|
|
120
|
+
|
|
121
|
+
moab_core, tags = define_moab_core_and_tags()
|
|
122
|
+
|
|
123
|
+
volume_sets_by_solid_id = {}
|
|
124
|
+
for material_tag, (solid_id, triangles_on_each_face) in zip(
|
|
125
|
+
material_tags, triangles_by_solid_by_face.items()
|
|
126
|
+
):
|
|
127
|
+
volume_set = moab_core.create_meshset()
|
|
128
|
+
volume_sets_by_solid_id[solid_id] = volume_set
|
|
3
129
|
|
|
4
|
-
|
|
5
|
-
|
|
130
|
+
added_surfaces_ids = {}
|
|
131
|
+
for material_tag, (solid_id, triangles_on_each_face) in zip(
|
|
132
|
+
material_tags, triangles_by_solid_by_face.items()
|
|
133
|
+
):
|
|
134
|
+
volume_set = volume_sets_by_solid_id[solid_id]
|
|
6
135
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
136
|
+
moab_core.tag_set_data(tags["global_id"], volume_set, solid_id)
|
|
137
|
+
moab_core.tag_set_data(tags["geom_dimension"], volume_set, 3)
|
|
138
|
+
moab_core.tag_set_data(tags["category"], volume_set, "Volume")
|
|
139
|
+
|
|
140
|
+
group_set = moab_core.create_meshset()
|
|
141
|
+
moab_core.tag_set_data(tags["category"], group_set, "Group")
|
|
142
|
+
moab_core.tag_set_data(tags["name"], group_set, f"mat:{material_tag}")
|
|
143
|
+
moab_core.tag_set_data(tags["global_id"], group_set, solid_id)
|
|
144
|
+
# moab_core.tag_set_data(tags["geom_dimension"], group_set, 4)
|
|
145
|
+
|
|
146
|
+
for face_id, triangles_on_face in triangles_on_each_face.items():
|
|
147
|
+
if face_id not in added_surfaces_ids.keys():
|
|
148
|
+
face_set = moab_core.create_meshset()
|
|
149
|
+
moab_core.tag_set_data(tags["global_id"], face_set, face_id)
|
|
150
|
+
moab_core.tag_set_data(tags["geom_dimension"], face_set, 2)
|
|
151
|
+
moab_core.tag_set_data(tags["category"], face_set, "Surface")
|
|
152
|
+
|
|
153
|
+
if len(face_ids_with_solid_ids[face_id]) == 2:
|
|
154
|
+
other_solid_id = face_ids_with_solid_ids[face_id][1]
|
|
155
|
+
other_volume_set = volume_sets_by_solid_id[other_solid_id]
|
|
156
|
+
sense_data = np.array([other_volume_set, volume_set], dtype="uint64")
|
|
157
|
+
else:
|
|
158
|
+
sense_data = np.array([volume_set, 0], dtype="uint64")
|
|
159
|
+
|
|
160
|
+
moab_core.tag_set_data(tags["surf_sense"], face_set, sense_data)
|
|
161
|
+
|
|
162
|
+
moab_verts = moab_core.create_vertices(vertices)
|
|
163
|
+
moab_core.add_entity(face_set, moab_verts)
|
|
164
|
+
|
|
165
|
+
for triangle in triangles_on_face:
|
|
166
|
+
tri = (
|
|
167
|
+
moab_verts[int(triangle[0])],
|
|
168
|
+
moab_verts[int(triangle[1])],
|
|
169
|
+
moab_verts[int(triangle[2])],
|
|
170
|
+
)
|
|
171
|
+
|
|
172
|
+
moab_triangle = moab_core.create_element(types.MBTRI, tri)
|
|
173
|
+
moab_core.add_entity(face_set, moab_triangle)
|
|
174
|
+
|
|
175
|
+
added_surfaces_ids[face_id] = face_set
|
|
176
|
+
else:
|
|
177
|
+
face_set = added_surfaces_ids[face_id]
|
|
178
|
+
|
|
179
|
+
other_solid_id = face_ids_with_solid_ids[face_id][0]
|
|
180
|
+
|
|
181
|
+
other_volume_set = volume_sets_by_solid_id[other_solid_id]
|
|
182
|
+
|
|
183
|
+
sense_data = np.array([other_volume_set, volume_set], dtype="uint64")
|
|
184
|
+
moab_core.tag_set_data(tags["surf_sense"], face_set, sense_data)
|
|
185
|
+
|
|
186
|
+
moab_core.add_parent_child(volume_set, face_set)
|
|
187
|
+
|
|
188
|
+
moab_core.add_entity(group_set, volume_set)
|
|
189
|
+
|
|
190
|
+
all_sets = moab_core.get_entities_by_handle(0)
|
|
191
|
+
|
|
192
|
+
file_set = moab_core.create_meshset()
|
|
193
|
+
|
|
194
|
+
moab_core.add_entities(file_set, all_sets)
|
|
195
|
+
|
|
196
|
+
moab_core.write_file(h5m_filename)
|
|
197
|
+
|
|
198
|
+
return h5m_filename
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
def mesh_brep(
|
|
202
|
+
brep_object: str,
|
|
203
|
+
min_mesh_size: float = 1,
|
|
204
|
+
max_mesh_size: float = 10,
|
|
205
|
+
mesh_algorithm: int = 1,
|
|
206
|
+
):
|
|
207
|
+
"""Creates a conformal surface meshes of the volumes in a Brep file using
|
|
208
|
+
Gmsh.
|
|
209
|
+
|
|
210
|
+
Args:
|
|
211
|
+
brep_object: the filename of the Brep file to convert
|
|
212
|
+
min_mesh_size: the minimum mesh element size to use in Gmsh. Passed
|
|
213
|
+
into gmsh.option.setNumber("Mesh.MeshSizeMin", min_mesh_size)
|
|
214
|
+
max_mesh_size: the maximum mesh element size to use in Gmsh. Passed
|
|
215
|
+
into gmsh.option.setNumber("Mesh.MeshSizeMax", max_mesh_size)
|
|
216
|
+
mesh_algorithm: The Gmsh mesh algorithm number to use. Passed into
|
|
217
|
+
gmsh.option.setNumber("Mesh.Algorithm", mesh_algorithm)
|
|
218
|
+
|
|
219
|
+
Returns:
|
|
220
|
+
The resulting gmsh object and volumes
|
|
221
|
+
"""
|
|
222
|
+
|
|
223
|
+
gmsh.initialize()
|
|
224
|
+
gmsh.option.setNumber("General.Terminal", 1)
|
|
225
|
+
gmsh.model.add("made_with_brep_to_h5m_package")
|
|
226
|
+
volumes = gmsh.model.occ.importShapesNativePointer(brep_object)
|
|
227
|
+
gmsh.model.occ.synchronize()
|
|
228
|
+
|
|
229
|
+
gmsh.option.setNumber("Mesh.Algorithm", mesh_algorithm)
|
|
230
|
+
gmsh.option.setNumber("Mesh.MeshSizeMin", min_mesh_size)
|
|
231
|
+
gmsh.option.setNumber("Mesh.MeshSizeMax", max_mesh_size)
|
|
232
|
+
gmsh.model.mesh.generate(2)
|
|
233
|
+
|
|
234
|
+
return gmsh, volumes
|
|
235
|
+
|
|
236
|
+
|
|
237
|
+
def mesh_to_h5m_in_memory_method(
|
|
238
|
+
volumes,
|
|
239
|
+
material_tags: typing.Iterable[str],
|
|
240
|
+
h5m_filename: str = "dagmc.h5m",
|
|
241
|
+
msh_filename=None,
|
|
242
|
+
) -> str:
|
|
243
|
+
"""Converts gmsh volumes into a DAGMC h5m file.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
volumes: the volumes in the gmsh file, found with gmsh.model.occ.importShapes
|
|
247
|
+
material_tags: A list of material tags to tag the DAGMC volumes with.
|
|
248
|
+
Should be in the same order as the volumes
|
|
249
|
+
h5m_filename: the filename of the DAGMC h5m file to write
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
The filename of the h5m file produced
|
|
253
|
+
"""
|
|
254
|
+
|
|
255
|
+
if isinstance(material_tags, str):
|
|
256
|
+
msg = f"material_tags should be a list of strings, not a single string."
|
|
257
|
+
raise ValueError(msg)
|
|
258
|
+
|
|
259
|
+
if len(volumes) != len(material_tags):
|
|
260
|
+
msg = f"{len(volumes)} volumes found in Brep file is not equal to the number of material_tags {len(material_tags)} provided."
|
|
261
|
+
raise ValueError(msg)
|
|
262
|
+
|
|
263
|
+
n = 3 # number of verts in a triangles
|
|
264
|
+
triangles_by_solid_by_face = {}
|
|
265
|
+
for dim_and_vol in volumes:
|
|
266
|
+
# removes all groups so that the following getEntitiesForPhysicalGroup
|
|
267
|
+
# command only finds surfaces for the volume
|
|
268
|
+
gmsh.model.removePhysicalGroups()
|
|
269
|
+
|
|
270
|
+
vol_id = dim_and_vol[1]
|
|
271
|
+
entities_in_volume = gmsh.model.getAdjacencies(3, vol_id)
|
|
272
|
+
surfaces_in_volume = entities_in_volume[1]
|
|
273
|
+
ps = gmsh.model.addPhysicalGroup(2, surfaces_in_volume)
|
|
274
|
+
gmsh.model.setPhysicalName(2, ps, f"surfaces_on_volume_{vol_id}")
|
|
275
|
+
|
|
276
|
+
groups = gmsh.model.getPhysicalGroups()
|
|
277
|
+
group = groups[0]
|
|
278
|
+
# for group in groups:
|
|
279
|
+
dim = group[0]
|
|
280
|
+
tag = group[1]
|
|
281
|
+
|
|
282
|
+
surfaces = gmsh.model.getEntitiesForPhysicalGroup(dim, tag)
|
|
283
|
+
|
|
284
|
+
# nodes_in_all_surfaces = []
|
|
285
|
+
nodes_in_each_surface = {}
|
|
286
|
+
for surface in surfaces:
|
|
287
|
+
_, _, nodeTags = gmsh.model.mesh.getElements(2, surface)
|
|
288
|
+
nodeTags = nodeTags[0].tolist()
|
|
289
|
+
shifted_node_tags = []
|
|
290
|
+
for nodeTag in nodeTags:
|
|
291
|
+
shifted_node_tags.append(nodeTag - 1)
|
|
292
|
+
grouped_node_tags = [
|
|
293
|
+
shifted_node_tags[i : i + n] for i in range(0, len(shifted_node_tags), n)
|
|
294
|
+
]
|
|
295
|
+
nodes_in_each_surface[surface] = grouped_node_tags
|
|
296
|
+
triangles_by_solid_by_face[vol_id] = nodes_in_each_surface
|
|
297
|
+
|
|
298
|
+
_, all_coords, _ = gmsh.model.mesh.getNodes()
|
|
299
|
+
|
|
300
|
+
vertices = [all_coords[i : i + n].tolist() for i in range(0, len(all_coords), n)]
|
|
301
|
+
|
|
302
|
+
if msh_filename is not None:
|
|
303
|
+
gmsh.write(msh_filename)
|
|
304
|
+
|
|
305
|
+
gmsh.finalize()
|
|
306
|
+
|
|
307
|
+
# checks and fixes triangle fix_normals within vertices_to_h5m
|
|
308
|
+
return vertices_to_h5m(
|
|
309
|
+
vertices=vertices,
|
|
310
|
+
triangles_by_solid_by_face=triangles_by_solid_by_face,
|
|
311
|
+
material_tags=material_tags,
|
|
312
|
+
h5m_filename=h5m_filename,
|
|
313
|
+
)
|
|
314
|
+
|
|
315
|
+
|
|
316
|
+
def get_ids_from_assembly(assembly):
|
|
317
|
+
ids = []
|
|
318
|
+
for obj, name, loc, _ in assembly:
|
|
319
|
+
ids.append(name)
|
|
320
|
+
return ids
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
def get_ids_from_imprinted_assembly(solid_id_dict):
|
|
324
|
+
ids = []
|
|
325
|
+
for id in list(solid_id_dict.values()):
|
|
326
|
+
ids.append(id[0])
|
|
327
|
+
return ids
|
|
328
|
+
|
|
329
|
+
|
|
330
|
+
def order_material_ids_by_brep_order(original_ids, scrambled_id, material_tags):
|
|
331
|
+
material_tags_in_brep_order = []
|
|
332
|
+
for brep_id in scrambled_id:
|
|
333
|
+
id_of_solid_in_org = original_ids.index(brep_id)
|
|
334
|
+
material_tags_in_brep_order.append(material_tags[id_of_solid_in_org])
|
|
335
|
+
return material_tags_in_brep_order
|
|
336
|
+
|
|
337
|
+
|
|
338
|
+
def merge_surfaces(parts):
|
|
339
|
+
"""Merges surfaces in the geometry that are the same. More details on
|
|
340
|
+
the merging process in the DAGMC docs
|
|
341
|
+
https://svalinn.github.io/DAGMC/usersguide/cubit_basics.html"""
|
|
342
|
+
|
|
343
|
+
# solids = geometry.Solids()
|
|
344
|
+
|
|
345
|
+
bldr = OCP.BOPAlgo.BOPAlgo_Splitter()
|
|
346
|
+
|
|
347
|
+
if len(parts) == 1:
|
|
348
|
+
# merged_solid = cq.Compound(solids)
|
|
349
|
+
|
|
350
|
+
if isinstance(parts[0], (cq.occ_impl.shapes.Compound, cq.occ_impl.shapes.Solid)):
|
|
351
|
+
# stp file
|
|
352
|
+
return parts[0], parts[0].wrapped
|
|
353
|
+
else:
|
|
354
|
+
return parts[0], parts[0].toOCC()
|
|
355
|
+
|
|
356
|
+
# else:
|
|
357
|
+
for solid in parts:
|
|
358
|
+
# checks if solid is a compound as .val() is not needed for compounds
|
|
359
|
+
if isinstance(solid, (cq.occ_impl.shapes.Compound, cq.occ_impl.shapes.Solid)):
|
|
360
|
+
bldr.AddArgument(solid.wrapped)
|
|
361
|
+
else:
|
|
362
|
+
bldr.AddArgument(solid.val().wrapped)
|
|
363
|
+
|
|
364
|
+
bldr.SetNonDestructive(True)
|
|
365
|
+
|
|
366
|
+
bldr.Perform()
|
|
367
|
+
|
|
368
|
+
bldr.Images()
|
|
10
369
|
|
|
11
|
-
|
|
12
|
-
# from OCP.BRep import BRep_Tool
|
|
13
|
-
# from OCP.TopAbs import TopAbs_Orientation
|
|
370
|
+
merged_solid = cq.Compound(bldr.Shape())
|
|
14
371
|
|
|
15
|
-
|
|
16
|
-
from .brep_part_finder import (
|
|
17
|
-
get_ids_from_assembly,
|
|
18
|
-
get_ids_from_imprinted_assembly,
|
|
19
|
-
order_material_ids_by_brep_order,
|
|
20
|
-
)
|
|
372
|
+
return merged_solid, merged_solid.wrapped
|
|
21
373
|
|
|
22
374
|
|
|
23
375
|
class CadToDagmc:
|
|
@@ -45,7 +397,6 @@ class CadToDagmc:
|
|
|
45
397
|
Useful when converting the geometry to cm for use in neutronics
|
|
46
398
|
simulations.
|
|
47
399
|
"""
|
|
48
|
-
print(f"loading stp file {filename}")
|
|
49
400
|
part = importers.importStep(str(filename)).val()
|
|
50
401
|
|
|
51
402
|
if scale_factor == 1:
|
|
@@ -73,7 +424,6 @@ class CadToDagmc:
|
|
|
73
424
|
"""
|
|
74
425
|
|
|
75
426
|
if isinstance(object, cq.assembly.Assembly):
|
|
76
|
-
print("assembly found")
|
|
77
427
|
object = object.toCompound()
|
|
78
428
|
|
|
79
429
|
if isinstance(object, (cq.occ_impl.shapes.Compound, cq.occ_impl.shapes.Solid)):
|
|
@@ -93,23 +443,26 @@ class CadToDagmc:
|
|
|
93
443
|
self,
|
|
94
444
|
filename: str = "dagmc.h5m",
|
|
95
445
|
min_mesh_size: float = 1,
|
|
96
|
-
max_mesh_size: float =
|
|
446
|
+
max_mesh_size: float = 5,
|
|
97
447
|
mesh_algorithm: int = 1,
|
|
448
|
+
msh_filename: str = None,
|
|
98
449
|
):
|
|
99
450
|
assembly = cq.Assembly()
|
|
100
451
|
for part in self.parts:
|
|
101
452
|
assembly.add(part)
|
|
102
453
|
|
|
103
|
-
(
|
|
104
|
-
imprinted_assembly,
|
|
105
|
-
imprinted_solids_with_original_id,
|
|
106
|
-
) = cq.occ_impl.assembly.imprint(assembly)
|
|
454
|
+
imprinted_assembly, imprinted_solids_with_org_id = cq.occ_impl.assembly.imprint(assembly)
|
|
107
455
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
456
|
+
gmsh, volumes = mesh_brep(
|
|
457
|
+
brep_object=imprinted_assembly.wrapped._address(),
|
|
458
|
+
min_mesh_size=min_mesh_size,
|
|
459
|
+
max_mesh_size=max_mesh_size,
|
|
460
|
+
mesh_algorithm=mesh_algorithm,
|
|
111
461
|
)
|
|
112
462
|
|
|
463
|
+
original_ids = get_ids_from_assembly(assembly)
|
|
464
|
+
scrambled_ids = get_ids_from_imprinted_assembly(imprinted_solids_with_org_id)
|
|
465
|
+
|
|
113
466
|
# both id lists should be the same length as each other and the same
|
|
114
467
|
# length as the self.material_tags
|
|
115
468
|
|
|
@@ -117,55 +470,10 @@ class CadToDagmc:
|
|
|
117
470
|
original_ids, scrambled_ids, self.material_tags
|
|
118
471
|
)
|
|
119
472
|
|
|
120
|
-
gmsh, volumes = mesh_brep(
|
|
121
|
-
brep_object=imprinted_assembly.wrapped._address(),
|
|
122
|
-
min_mesh_size=min_mesh_size,
|
|
123
|
-
max_mesh_size=max_mesh_size,
|
|
124
|
-
mesh_algorithm=mesh_algorithm,
|
|
125
|
-
)
|
|
126
|
-
|
|
127
473
|
h5m_filename = mesh_to_h5m_in_memory_method(
|
|
128
474
|
volumes=volumes,
|
|
129
475
|
material_tags=material_tags_in_brep_order,
|
|
130
476
|
h5m_filename=filename,
|
|
477
|
+
msh_filename=msh_filename,
|
|
131
478
|
)
|
|
132
479
|
return h5m_filename
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def merge_surfaces(parts):
|
|
136
|
-
"""Merges surfaces in the geometry that are the same. More details on
|
|
137
|
-
the merging process in the DAGMC docs
|
|
138
|
-
https://svalinn.github.io/DAGMC/usersguide/cubit_basics.html"""
|
|
139
|
-
|
|
140
|
-
# solids = geometry.Solids()
|
|
141
|
-
|
|
142
|
-
bldr = OCP.BOPAlgo.BOPAlgo_Splitter()
|
|
143
|
-
|
|
144
|
-
if len(parts) == 1:
|
|
145
|
-
# merged_solid = cq.Compound(solids)
|
|
146
|
-
|
|
147
|
-
if isinstance(
|
|
148
|
-
parts[0], (cq.occ_impl.shapes.Compound, cq.occ_impl.shapes.Solid)
|
|
149
|
-
):
|
|
150
|
-
# stp file
|
|
151
|
-
return parts[0], parts[0].wrapped
|
|
152
|
-
else:
|
|
153
|
-
return parts[0], parts[0].toOCC()
|
|
154
|
-
|
|
155
|
-
# else:
|
|
156
|
-
for solid in parts:
|
|
157
|
-
# checks if solid is a compound as .val() is not needed for compounds
|
|
158
|
-
if isinstance(solid, (cq.occ_impl.shapes.Compound, cq.occ_impl.shapes.Solid)):
|
|
159
|
-
bldr.AddArgument(solid.wrapped)
|
|
160
|
-
else:
|
|
161
|
-
bldr.AddArgument(solid.val().wrapped)
|
|
162
|
-
|
|
163
|
-
bldr.SetNonDestructive(True)
|
|
164
|
-
|
|
165
|
-
bldr.Perform()
|
|
166
|
-
|
|
167
|
-
bldr.Images()
|
|
168
|
-
|
|
169
|
-
merged_solid = cq.Compound(bldr.Shape())
|
|
170
|
-
|
|
171
|
-
return merged_solid, merged_solid.wrapped
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cad-to-dagmc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.1
|
|
4
4
|
Summary: Converts CAD files to a DAGMC h5m file
|
|
5
5
|
Author-email: Jonathan Shimwell <mail@jshimwell.com>
|
|
6
6
|
Project-URL: Homepage, https://github.com/fusion-energy/cad_to_dagmc
|
|
@@ -20,46 +20,53 @@ Requires-Dist: pytest ; extra == 'tests'
|
|
|
20
20
|
|
|
21
21
|
[](https://www.python.org)
|
|
22
22
|
|
|
23
|
-
[](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/ci_with_benchmarks.yml) Testing package and running examples
|
|
24
24
|
|
|
25
|
-
[](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/ci_with_benchmarks.yml) Testing with [Model Benchmark Zoo](https://github.com/fusion-energy/model_benchmark_zoo)
|
|
26
26
|
|
|
27
|
+
[](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/python-publish.yml)
|
|
27
28
|
|
|
28
29
|
[](https://pypi.org/project/cad_to_dagmc/)
|
|
29
30
|
|
|
30
|
-
___
|
|
31
31
|
|
|
32
|
-
A minimal package that uses CadQuery functionality to convert
|
|
32
|
+
A minimal package that uses CadQuery functionality to convert CAD geometry to [DAGMC](https://github.com/svalinn/DAGMC/) h5m files
|
|
33
33
|
|
|
34
|
-
This particular method of producing DAGMC compatible h5m files from CAD geometry
|
|
35
|
-
is intended to convert STP files or [CadQuery](https://cadquery.readthedocs.io) objects to h5m file.
|
|
34
|
+
This particular method of producing DAGMC compatible h5m files from CAD geometry is intended to convert STP files or [CadQuery](https://cadquery.readthedocs.io) objects to a DAGMC compatible h5m file.
|
|
36
35
|
|
|
37
|
-
|
|
38
|
-
This allows for the addition of parametric geometry to static geometry.
|
|
36
|
+
The resulting DAGMC geometry can then be used for simulations in [OpenMC](https://github.com/openmc-dev/openmc/) or [other supported codes](https://svalinn.github.io/DAGMC/).
|
|
39
37
|
|
|
40
|
-
|
|
38
|
+
This package is tested with [pytest tests](https://github.com/fusion-energy/cad_to_dagmc/tree/main/tests) and also the DAGMC geometry made with this package is compared to simulation carried out with native constructive solid geometry, see [Model Benchmark Zoo](https://github.com/fusion-energy/model_benchmark_zoo) for more details.
|
|
41
39
|
|
|
42
|
-
|
|
40
|
+
Also checkout these other packages that also create DAGMC geometry [CAD-to-OpenMC](https://github.com/openmsr/CAD_to_OpenMC), [Stellarmesh](https://github.com/Thea-Energy/stellarmesh)
|
|
43
41
|
|
|
42
|
+
# Installation prerequisite
|
|
44
43
|
|
|
45
|
-
|
|
44
|
+
In principle, any Conda/Mamba distribution will work. A few Conda/Mamba options are:
|
|
45
|
+
- [Mambaforge](https://github.com/conda-forge/miniforge#mambaforge)
|
|
46
|
+
- [Miniforge](https://github.com/conda-forge/miniforge#miniforge-pypy3)
|
|
47
|
+
- [Anaconda](https://www.anaconda.com/download)
|
|
48
|
+
- [Miniconda](https://docs.conda.io/en/latest/miniconda.html)
|
|
46
49
|
|
|
47
|
-
This example uses Conda to install some dependencies that are not available via PyPi.
|
|
48
50
|
|
|
49
|
-
|
|
51
|
+
# Install using Mamba and pip
|
|
52
|
+
|
|
53
|
+
This example assumes you have installed the MambaForge option or separately
|
|
54
|
+
installed Mamba with ```conda install -c conda-forge mamba -y```
|
|
55
|
+
|
|
56
|
+
Create a new conda environment, I've chosen Python 3.9 here but new versions are
|
|
57
|
+
also supported.
|
|
50
58
|
```bash
|
|
51
|
-
|
|
59
|
+
mamba create --name new_env python=3.9 -y
|
|
52
60
|
```
|
|
53
61
|
|
|
54
62
|
Activate the environment
|
|
55
63
|
```bash
|
|
56
|
-
|
|
64
|
+
mamba activate new_env
|
|
57
65
|
```
|
|
58
66
|
|
|
59
67
|
Install the dependencies
|
|
60
68
|
```bash
|
|
61
|
-
|
|
62
|
-
conda install -c cadquery -c conda-forge cadquery=master --no-deps -y
|
|
69
|
+
mamba install -c cadquery -c conda-forge moab gmsh python-gmsh cadquery=master -y
|
|
63
70
|
```
|
|
64
71
|
|
|
65
72
|
Then you can install the cad_to_dagmc package with ```pip```
|
|
@@ -69,30 +76,27 @@ pip install cad_to_dagmc
|
|
|
69
76
|
|
|
70
77
|
You may also want to install OpenMC with DAGMC to make use of the h5m geometry files produced in simulations. However you could also use other supported particle transport codes such as MCNP, FLUKA and others [link to DAGMC documentation](https://svalinn.github.io/DAGMC/).You can run ```conda install -c conda-forge openmc``` however this more specific command makes sure the latest version of OpenMC which contains DAGMC is chosen by conda / mamba
|
|
71
78
|
```bash
|
|
72
|
-
|
|
79
|
+
mamba install -c conda-forge -y "openmc=0.13.3=dagmc*nompi*"
|
|
73
80
|
```
|
|
74
81
|
|
|
75
82
|
|
|
76
|
-
# Install using
|
|
83
|
+
# Install using Conda and pip
|
|
77
84
|
|
|
78
|
-
This example uses
|
|
85
|
+
This example uses Conda to install some dependencies that are not available via PyPi.
|
|
79
86
|
|
|
80
|
-
Create a new conda environment
|
|
81
|
-
also supported.
|
|
87
|
+
Create a new conda environment
|
|
82
88
|
```bash
|
|
83
89
|
conda create --name new_env python=3.9 -y
|
|
84
90
|
```
|
|
85
91
|
|
|
86
92
|
Activate the environment
|
|
87
93
|
```bash
|
|
88
|
-
|
|
94
|
+
conda activate new_env
|
|
89
95
|
```
|
|
90
96
|
|
|
91
97
|
Install the dependencies
|
|
92
98
|
```bash
|
|
93
|
-
conda install -c conda-forge
|
|
94
|
-
mamba install -c conda-forge moab multimethod typish ezdxf nptyping nlopt casadi gmsh python-gmsh ocp>=7.7.1 -y
|
|
95
|
-
mamba install -c cadquery -c conda-forge cadquery=master --no-deps -y
|
|
99
|
+
conda install -c cadquery -c conda-forge moab gmsh python-gmsh cadquery=master -y
|
|
96
100
|
```
|
|
97
101
|
|
|
98
102
|
Then you can install the cad_to_dagmc package with ```pip```
|
|
@@ -102,9 +106,11 @@ pip install cad_to_dagmc
|
|
|
102
106
|
|
|
103
107
|
You may also want to install OpenMC with DAGMC to make use of the h5m geometry files produced in simulations. However you could also use other supported particle transport codes such as MCNP, FLUKA and others [link to DAGMC documentation](https://svalinn.github.io/DAGMC/).You can run ```conda install -c conda-forge openmc``` however this more specific command makes sure the latest version of OpenMC which contains DAGMC is chosen by conda / mamba
|
|
104
108
|
```bash
|
|
105
|
-
|
|
109
|
+
conda install -c conda-forge -y "openmc=0.13.3=dagmc*nompi*"
|
|
106
110
|
```
|
|
107
111
|
|
|
112
|
+
|
|
113
|
+
|
|
108
114
|
# Usage - creation of DAGMC h5m files
|
|
109
115
|
|
|
110
116
|
For examples see the [examples folder](https://github.com/fusion-energy/cad_to_dagmc/tree/main/examples)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
_version.py,sha256=8W5N0WKS0YIWUpfry5TouisDYjsMUIZ7Vc0crGGGQQU,411
|
|
2
|
+
cad_to_dagmc/__init__.py,sha256=fskHUTyCunSpnpJUvBfAYjx4uwDKXHTTiMP6GqnFRf0,494
|
|
3
|
+
cad_to_dagmc/core.py,sha256=rLJT6RhmaqQ2NQm9Nyxj1pqSz5TC0pgET0CvpQFI3TM,16643
|
|
4
|
+
cad_to_dagmc-0.5.1.dist-info/LICENSE,sha256=B8kznH_777JVNZ3HOKDc4Tj24F7wJ68ledaNYeL9sCw,1070
|
|
5
|
+
cad_to_dagmc-0.5.1.dist-info/METADATA,sha256=4RxJjQNV7RKMmB_xprO8LJ_OyuLSMlklUtmqaQvtyvo,5583
|
|
6
|
+
cad_to_dagmc-0.5.1.dist-info/WHEEL,sha256=oiQVh_5PnQM0E3gPdiz09WCNmwiHDMaGer_elqB3coM,92
|
|
7
|
+
cad_to_dagmc-0.5.1.dist-info/top_level.txt,sha256=zTi8C64SEBsE5WOtPovnxhOzt-E6Oc5nC3RW6M_5aEA,22
|
|
8
|
+
cad_to_dagmc-0.5.1.dist-info/RECORD,,
|
cad_to_dagmc/brep_part_finder.py
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import cadquery as cq
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
def convert_shape_to_iterable_of_shapes(shapes):
|
|
5
|
-
if isinstance(shapes, cq.occ_impl.shapes.Compound):
|
|
6
|
-
# brep route
|
|
7
|
-
iterable_solids = shapes.Solids()
|
|
8
|
-
elif isinstance(shapes, cq.Workplane):
|
|
9
|
-
# workplane route
|
|
10
|
-
iterable_solids = shapes.val().Solids()
|
|
11
|
-
else:
|
|
12
|
-
iterable_solids = shapes.Solids()
|
|
13
|
-
|
|
14
|
-
return iterable_solids
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
def get_ids_from_assembly(assembly):
|
|
18
|
-
ids = []
|
|
19
|
-
for obj, name, loc, _ in assembly:
|
|
20
|
-
ids.append(name)
|
|
21
|
-
return ids
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def get_ids_from_imprinted_assembly(solid_id_dict):
|
|
25
|
-
ids = []
|
|
26
|
-
for id in list(solid_id_dict.values()):
|
|
27
|
-
print(id[0])
|
|
28
|
-
ids.append(id[0])
|
|
29
|
-
return ids
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
def order_material_ids_by_brep_order(original_ids, scrambled_id, material_tags):
|
|
33
|
-
material_tags_in_brep_order = []
|
|
34
|
-
for brep_id in scrambled_id:
|
|
35
|
-
id_of_solid_in_org = original_ids.index(brep_id)
|
|
36
|
-
material_tags_in_brep_order.append(material_tags[id_of_solid_in_org])
|
|
37
|
-
return material_tags_in_brep_order
|
cad_to_dagmc/brep_to_h5m.py
DELETED
|
@@ -1,118 +0,0 @@
|
|
|
1
|
-
import gmsh
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from .vertices_to_h5m import vertices_to_h5m
|
|
4
|
-
import typing
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
def mesh_brep(
|
|
8
|
-
brep_object: str,
|
|
9
|
-
min_mesh_size: float = 30,
|
|
10
|
-
max_mesh_size: float = 10,
|
|
11
|
-
mesh_algorithm: int = 1,
|
|
12
|
-
):
|
|
13
|
-
"""Creates a conformal surface meshes of the volumes in a Brep file using
|
|
14
|
-
Gmsh.
|
|
15
|
-
|
|
16
|
-
Args:
|
|
17
|
-
brep_object: the filename of the Brep file to convert
|
|
18
|
-
min_mesh_size: the minimum mesh element size to use in Gmsh. Passed
|
|
19
|
-
into gmsh.option.setNumber("Mesh.MeshSizeMin", min_mesh_size)
|
|
20
|
-
max_mesh_size: the maximum mesh element size to use in Gmsh. Passed
|
|
21
|
-
into gmsh.option.setNumber("Mesh.MeshSizeMax", max_mesh_size)
|
|
22
|
-
mesh_algorithm: The Gmsh mesh algorithm number to use. Passed into
|
|
23
|
-
gmsh.option.setNumber("Mesh.Algorithm", mesh_algorithm)
|
|
24
|
-
|
|
25
|
-
Returns:
|
|
26
|
-
The gmsh object and volumes in Brep file
|
|
27
|
-
"""
|
|
28
|
-
|
|
29
|
-
gmsh.initialize()
|
|
30
|
-
gmsh.option.setNumber("General.Terminal", 1)
|
|
31
|
-
gmsh.model.add("made_with_brep_to_h5m_package")
|
|
32
|
-
volumes = gmsh.model.occ.importShapesNativePointer(brep_object)
|
|
33
|
-
# gmsh.model.occ.importShapes(brep_object)
|
|
34
|
-
gmsh.model.occ.synchronize()
|
|
35
|
-
|
|
36
|
-
gmsh.option.setNumber("Mesh.Algorithm", mesh_algorithm)
|
|
37
|
-
gmsh.option.setNumber("Mesh.MeshSizeMin", min_mesh_size)
|
|
38
|
-
gmsh.option.setNumber("Mesh.MeshSizeMax", max_mesh_size)
|
|
39
|
-
gmsh.model.mesh.generate(2)
|
|
40
|
-
|
|
41
|
-
return gmsh, volumes
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
def mesh_to_h5m_in_memory_method(
|
|
45
|
-
volumes,
|
|
46
|
-
material_tags: typing.Iterable[str],
|
|
47
|
-
h5m_filename: str = "dagmc.h5m",
|
|
48
|
-
) -> str:
|
|
49
|
-
"""Converts gmsh volumes into a DAGMC h5m file.
|
|
50
|
-
|
|
51
|
-
Args:
|
|
52
|
-
volumes: the volumes in the gmsh file, found with gmsh.model.occ.importShapes
|
|
53
|
-
material_tags: A list of material tags to tag the DAGMC volumes with.
|
|
54
|
-
Should be in the same order as the volumes
|
|
55
|
-
h5m_filename: the filename of the DAGMC h5m file to write
|
|
56
|
-
|
|
57
|
-
Returns:
|
|
58
|
-
The filename of the h5m file produced
|
|
59
|
-
"""
|
|
60
|
-
|
|
61
|
-
if isinstance(material_tags, str):
|
|
62
|
-
msg = f"material_tags should be a list of strings, not a single string."
|
|
63
|
-
raise ValueError(msg)
|
|
64
|
-
|
|
65
|
-
if len(volumes) != len(material_tags):
|
|
66
|
-
msg = f"{len(volumes)} volumes found in Brep file is not equal to the number of material_tags {len(material_tags)} provided."
|
|
67
|
-
raise ValueError(msg)
|
|
68
|
-
|
|
69
|
-
n = 3 # number of verts in a triangles
|
|
70
|
-
nodes_in_each_pg = []
|
|
71
|
-
for dim_and_vol in volumes:
|
|
72
|
-
# removes all groups so that the following getEntitiesForPhysicalGroup
|
|
73
|
-
# command only finds surfaces for the volume
|
|
74
|
-
gmsh.model.removePhysicalGroups()
|
|
75
|
-
|
|
76
|
-
vol_id = dim_and_vol[1]
|
|
77
|
-
entities_in_volume = gmsh.model.getAdjacencies(3, vol_id)
|
|
78
|
-
surfaces_in_volume = entities_in_volume[1]
|
|
79
|
-
ps = gmsh.model.addPhysicalGroup(2, surfaces_in_volume)
|
|
80
|
-
gmsh.model.setPhysicalName(2, ps, f"surfaces_on_volume_{vol_id}")
|
|
81
|
-
|
|
82
|
-
groups = gmsh.model.getPhysicalGroups()
|
|
83
|
-
group = groups[0]
|
|
84
|
-
# for group in groups:
|
|
85
|
-
dim = group[0]
|
|
86
|
-
tag = group[1]
|
|
87
|
-
|
|
88
|
-
surfaces = gmsh.model.getEntitiesForPhysicalGroup(dim, tag)
|
|
89
|
-
|
|
90
|
-
nodes_in_all_surfaces = []
|
|
91
|
-
for surface in surfaces:
|
|
92
|
-
_, _, nodeTags = gmsh.model.mesh.getElements(2, surface)
|
|
93
|
-
nodeTags = nodeTags[0].tolist()
|
|
94
|
-
shifted_node_tags = []
|
|
95
|
-
for nodeTag in nodeTags:
|
|
96
|
-
shifted_node_tags.append(nodeTag - 1)
|
|
97
|
-
grouped_node_tags = [
|
|
98
|
-
shifted_node_tags[i : i + n]
|
|
99
|
-
for i in range(0, len(shifted_node_tags), n)
|
|
100
|
-
]
|
|
101
|
-
nodes_in_all_surfaces += grouped_node_tags
|
|
102
|
-
nodes_in_each_pg.append(nodes_in_all_surfaces)
|
|
103
|
-
|
|
104
|
-
_, all_coords, _ = gmsh.model.mesh.getNodes()
|
|
105
|
-
|
|
106
|
-
GroupedCoords = [
|
|
107
|
-
all_coords[i : i + n].tolist() for i in range(0, len(all_coords), n)
|
|
108
|
-
]
|
|
109
|
-
|
|
110
|
-
gmsh.finalize()
|
|
111
|
-
|
|
112
|
-
# checks and fixes triangle fix_normals within vertices_to_h5m
|
|
113
|
-
return vertices_to_h5m(
|
|
114
|
-
vertices=GroupedCoords,
|
|
115
|
-
triangles=nodes_in_each_pg,
|
|
116
|
-
material_tags=material_tags,
|
|
117
|
-
h5m_filename=h5m_filename,
|
|
118
|
-
)
|
cad_to_dagmc/vertices_to_h5m.py
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
from typing import Iterable, Tuple, Union
|
|
2
|
-
|
|
3
|
-
import numpy as np
|
|
4
|
-
import trimesh
|
|
5
|
-
from pymoab import core, types
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
def fix_normals(vertices, triangles_in_each_volume):
|
|
9
|
-
fixed_triangles = []
|
|
10
|
-
for triangles in triangles_in_each_volume:
|
|
11
|
-
fixed_triangles.append(fix_normal(vertices, triangles))
|
|
12
|
-
return fixed_triangles
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
def fix_normal(vertices, triangles):
|
|
16
|
-
# for triangles in triangles_in_each_volume:
|
|
17
|
-
mesh = trimesh.Trimesh(vertices=vertices, faces=triangles, process=False)
|
|
18
|
-
|
|
19
|
-
mesh.fix_normals()
|
|
20
|
-
|
|
21
|
-
return mesh.faces
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def _define_moab_core_and_tags() -> Tuple[core.Core, dict]:
|
|
25
|
-
"""Creates a MOAB Core instance which can be built up by adding sets of
|
|
26
|
-
triangles to the instance
|
|
27
|
-
|
|
28
|
-
Returns:
|
|
29
|
-
(pymoab Core): A pymoab.core.Core() instance
|
|
30
|
-
(pymoab tag_handle): A pymoab.core.tag_get_handle() instance
|
|
31
|
-
"""
|
|
32
|
-
|
|
33
|
-
# create pymoab instance
|
|
34
|
-
moab_core = core.Core()
|
|
35
|
-
|
|
36
|
-
tags = dict()
|
|
37
|
-
|
|
38
|
-
sense_tag_name = "GEOM_SENSE_2"
|
|
39
|
-
sense_tag_size = 2
|
|
40
|
-
tags["surf_sense"] = moab_core.tag_get_handle(
|
|
41
|
-
sense_tag_name,
|
|
42
|
-
sense_tag_size,
|
|
43
|
-
types.MB_TYPE_HANDLE,
|
|
44
|
-
types.MB_TAG_SPARSE,
|
|
45
|
-
create_if_missing=True,
|
|
46
|
-
)
|
|
47
|
-
|
|
48
|
-
tags["category"] = moab_core.tag_get_handle(
|
|
49
|
-
types.CATEGORY_TAG_NAME,
|
|
50
|
-
types.CATEGORY_TAG_SIZE,
|
|
51
|
-
types.MB_TYPE_OPAQUE,
|
|
52
|
-
types.MB_TAG_SPARSE,
|
|
53
|
-
create_if_missing=True,
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
tags["name"] = moab_core.tag_get_handle(
|
|
57
|
-
types.NAME_TAG_NAME,
|
|
58
|
-
types.NAME_TAG_SIZE,
|
|
59
|
-
types.MB_TYPE_OPAQUE,
|
|
60
|
-
types.MB_TAG_SPARSE,
|
|
61
|
-
create_if_missing=True,
|
|
62
|
-
)
|
|
63
|
-
|
|
64
|
-
tags["geom_dimension"] = moab_core.tag_get_handle(
|
|
65
|
-
types.GEOM_DIMENSION_TAG_NAME,
|
|
66
|
-
1,
|
|
67
|
-
types.MB_TYPE_INTEGER,
|
|
68
|
-
types.MB_TAG_DENSE,
|
|
69
|
-
create_if_missing=True,
|
|
70
|
-
)
|
|
71
|
-
|
|
72
|
-
# Global ID is a default tag, just need the name to retrieve
|
|
73
|
-
tags["global_id"] = moab_core.tag_get_handle(types.GLOBAL_ID_TAG_NAME)
|
|
74
|
-
|
|
75
|
-
return moab_core, tags
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def prepare_moab_core(
|
|
79
|
-
moab_core,
|
|
80
|
-
surface_id,
|
|
81
|
-
volume_id,
|
|
82
|
-
tags,
|
|
83
|
-
):
|
|
84
|
-
surface_set = moab_core.create_meshset()
|
|
85
|
-
volume_set = moab_core.create_meshset()
|
|
86
|
-
|
|
87
|
-
# recent versions of MOAB handle this automatically
|
|
88
|
-
# but best to go ahead and do it manually
|
|
89
|
-
moab_core.tag_set_data(tags["global_id"], volume_set, volume_id)
|
|
90
|
-
|
|
91
|
-
moab_core.tag_set_data(tags["global_id"], surface_set, surface_id)
|
|
92
|
-
|
|
93
|
-
# set geom IDs
|
|
94
|
-
moab_core.tag_set_data(tags["geom_dimension"], volume_set, 3)
|
|
95
|
-
moab_core.tag_set_data(tags["geom_dimension"], surface_set, 2)
|
|
96
|
-
|
|
97
|
-
# set category tag values
|
|
98
|
-
moab_core.tag_set_data(tags["category"], volume_set, "Volume")
|
|
99
|
-
moab_core.tag_set_data(tags["category"], surface_set, "Surface")
|
|
100
|
-
|
|
101
|
-
# establish parent-child relationship
|
|
102
|
-
moab_core.add_parent_child(volume_set, surface_set)
|
|
103
|
-
|
|
104
|
-
# set surface sense
|
|
105
|
-
sense_data = [volume_set, np.uint64(0)]
|
|
106
|
-
moab_core.tag_set_data(tags["surf_sense"], surface_set, sense_data)
|
|
107
|
-
|
|
108
|
-
return moab_core, surface_set, volume_set
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
def add_vertices_to_moab_core(moab_core, vertices, surface_set):
|
|
112
|
-
moab_verts = moab_core.create_vertices(vertices)
|
|
113
|
-
|
|
114
|
-
moab_core.add_entity(surface_set, moab_verts)
|
|
115
|
-
return moab_core, moab_verts
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def add_triangles_to_moab_core(
|
|
119
|
-
material_tag, surface_set, moab_core, tags, triangles, moab_verts, volume_set
|
|
120
|
-
):
|
|
121
|
-
for triangle in triangles:
|
|
122
|
-
tri = (
|
|
123
|
-
moab_verts[int(triangle[0])],
|
|
124
|
-
moab_verts[int(triangle[1])],
|
|
125
|
-
moab_verts[int(triangle[2])],
|
|
126
|
-
)
|
|
127
|
-
|
|
128
|
-
moab_triangle = moab_core.create_element(types.MBTRI, tri)
|
|
129
|
-
moab_core.add_entity(surface_set, moab_triangle)
|
|
130
|
-
|
|
131
|
-
group_set = moab_core.create_meshset()
|
|
132
|
-
|
|
133
|
-
moab_core.tag_set_data(tags["category"], group_set, "Group")
|
|
134
|
-
|
|
135
|
-
moab_core.tag_set_data(tags["name"], group_set, f"mat:{material_tag}")
|
|
136
|
-
|
|
137
|
-
moab_core.tag_set_data(tags["geom_dimension"], group_set, 4)
|
|
138
|
-
|
|
139
|
-
moab_core.add_entity(group_set, volume_set)
|
|
140
|
-
|
|
141
|
-
return moab_core
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
def vertices_to_h5m(
|
|
145
|
-
vertices: Union[
|
|
146
|
-
Iterable[Tuple[float, float, float]], Iterable["cadquery.occ_impl.geom.Vector"]
|
|
147
|
-
],
|
|
148
|
-
triangles: Iterable[Tuple[int, int, int]],
|
|
149
|
-
material_tags: Iterable[str],
|
|
150
|
-
h5m_filename="dagmc.h5m",
|
|
151
|
-
):
|
|
152
|
-
"""Converts vertices and triangle sets into a tagged h5m file compatible
|
|
153
|
-
with DAGMC enabled neutronics simulations
|
|
154
|
-
|
|
155
|
-
Args:
|
|
156
|
-
vertices:
|
|
157
|
-
triangles:
|
|
158
|
-
material_tags:
|
|
159
|
-
h5m_filename:
|
|
160
|
-
"""
|
|
161
|
-
|
|
162
|
-
if len(material_tags) != len(triangles):
|
|
163
|
-
msg = f"The number of material_tags provided is {len(material_tags)} and the number of sets of triangles is {len(triangles)}. You must provide one material_tag for every triangle set"
|
|
164
|
-
raise ValueError(msg)
|
|
165
|
-
|
|
166
|
-
# limited attribute checking to see if user passed in a list of CadQuery vectors
|
|
167
|
-
if (
|
|
168
|
-
hasattr(vertices[0], "x")
|
|
169
|
-
and hasattr(vertices[0], "y")
|
|
170
|
-
and hasattr(vertices[0], "z")
|
|
171
|
-
):
|
|
172
|
-
vertices_floats = []
|
|
173
|
-
for vert in vertices:
|
|
174
|
-
vertices_floats.append((vert.x, vert.y, vert.z))
|
|
175
|
-
else:
|
|
176
|
-
vertices_floats = vertices
|
|
177
|
-
|
|
178
|
-
triangles = fix_normals(
|
|
179
|
-
vertices=vertices_floats, triangles_in_each_volume=triangles
|
|
180
|
-
)
|
|
181
|
-
|
|
182
|
-
moab_core, tags = _define_moab_core_and_tags()
|
|
183
|
-
|
|
184
|
-
for vol_id, material_tag in enumerate(material_tags, 1):
|
|
185
|
-
moab_core, surface_set, volume_set = prepare_moab_core(
|
|
186
|
-
moab_core, surface_id=vol_id, volume_id=vol_id, tags=tags
|
|
187
|
-
)
|
|
188
|
-
|
|
189
|
-
moab_core, moab_verts = add_vertices_to_moab_core(
|
|
190
|
-
moab_core, vertices_floats, surface_set
|
|
191
|
-
)
|
|
192
|
-
|
|
193
|
-
moab_core = add_triangles_to_moab_core(
|
|
194
|
-
material_tag,
|
|
195
|
-
surface_set,
|
|
196
|
-
moab_core,
|
|
197
|
-
tags,
|
|
198
|
-
triangles[vol_id - 1],
|
|
199
|
-
moab_verts,
|
|
200
|
-
volume_set,
|
|
201
|
-
)
|
|
202
|
-
|
|
203
|
-
all_sets = moab_core.get_entities_by_handle(0)
|
|
204
|
-
|
|
205
|
-
file_set = moab_core.create_meshset()
|
|
206
|
-
|
|
207
|
-
moab_core.add_entities(file_set, all_sets)
|
|
208
|
-
|
|
209
|
-
moab_core.write_file(h5m_filename)
|
|
210
|
-
|
|
211
|
-
return h5m_filename
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
_version.py,sha256=QiCQVGOicQZY3DBr4tYPU9egzT1VgzOJGfLt9Q26uyU,160
|
|
2
|
-
cad_to_dagmc/__init__.py,sha256=PgkpCP8unzhcoyvw-lKpy5HLy2bnUNmFHS508_bsCCE,593
|
|
3
|
-
cad_to_dagmc/brep_part_finder.py,sha256=by2wnjo_KrTZaihFP5m5Z_sZJSdtEef7GS4nvpwqNrc,1020
|
|
4
|
-
cad_to_dagmc/brep_to_h5m.py,sha256=4w7xaO0uJU5c8PoQFtDoPUyzWart7pdSpynU1Rcv7xY,4107
|
|
5
|
-
cad_to_dagmc/core.py,sha256=XNXmEn06VellMwEqTXiCKRLVPN7NRDG3X0OQZXM2cOE,5594
|
|
6
|
-
cad_to_dagmc/vertices_to_h5m.py,sha256=h7KI2fofhBlyTMRdb0FXUO12SxW9MtnNEgwdCyNCPmk,5997
|
|
7
|
-
cad_to_dagmc-0.4.0.dist-info/LICENSE,sha256=B8kznH_777JVNZ3HOKDc4Tj24F7wJ68ledaNYeL9sCw,1070
|
|
8
|
-
cad_to_dagmc-0.4.0.dist-info/METADATA,sha256=9iMhi-El25ZzKZL1sKTQqwDQO5t2zd-8DEA5-acacgA,4545
|
|
9
|
-
cad_to_dagmc-0.4.0.dist-info/WHEEL,sha256=pkctZYzUS4AYVn6dJ-7367OJZivF2e8RA9b_ZBjif18,92
|
|
10
|
-
cad_to_dagmc-0.4.0.dist-info/top_level.txt,sha256=zTi8C64SEBsE5WOtPovnxhOzt-E6Oc5nC3RW6M_5aEA,22
|
|
11
|
-
cad_to_dagmc-0.4.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|