cad-to-dagmc 0.5.0__py3-none-any.whl → 0.6.0__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.
_version.py CHANGED
@@ -2,7 +2,15 @@
2
2
  # don't change, don't track in version control
3
3
  TYPE_CHECKING = False
4
4
  if TYPE_CHECKING:
5
- from typing import Tuple
5
+ from typing import Tuple, Union
6
+ VERSION_TUPLE = Tuple[Union[int, str], ...]
7
+ else:
8
+ VERSION_TUPLE = object
6
9
 
7
- __version__ = version = '0.5.0' # type: str
8
- __version_tuple__ = version_tuple = (0, 5, 0) # type: Tuple[int | str, ...]
10
+ version: str
11
+ __version__: str
12
+ __version_tuple__: VERSION_TUPLE
13
+ version_tuple: VERSION_TUPLE
14
+
15
+ __version__ = version = '0.6.0'
16
+ __version_tuple__ = version_tuple = (0, 6, 0)
cad_to_dagmc/__init__.py CHANGED
@@ -13,9 +13,4 @@ except PackageNotFoundError:
13
13
 
14
14
  __all__ = ["__version__"]
15
15
 
16
- from .core import CadToDagmc
17
- from .vertices_to_h5m import vertices_to_h5m
18
- from .brep_part_finder import *
19
- from .brep_to_h5m import *
20
-
21
- [CadToDagmc, vertices_to_h5m]
16
+ from .core import *
cad_to_dagmc/core.py CHANGED
@@ -1,38 +1,325 @@
1
1
  import typing
2
+
3
+ import cadquery as cq
4
+ import gmsh
5
+ import numpy as np
2
6
  from cadquery import importers
7
+ from pymoab import core, types
8
+
9
+
10
+ def _define_moab_core_and_tags() -> typing.Tuple[core.Core, dict]:
11
+ """Creates a MOAB Core instance which can be built up by adding sets of
12
+ triangles to the instance
13
+
14
+ Returns:
15
+ (pymoab Core): A pymoab.core.Core() instance
16
+ (pymoab tag_handle): A pymoab.core.tag_get_handle() instance
17
+ """
18
+
19
+ # create pymoab instance
20
+ moab_core = core.Core()
21
+
22
+ tags = dict()
23
+
24
+ sense_tag_name = "GEOM_SENSE_2"
25
+ sense_tag_size = 2
26
+ tags["surf_sense"] = moab_core.tag_get_handle(
27
+ sense_tag_name,
28
+ sense_tag_size,
29
+ types.MB_TYPE_HANDLE,
30
+ types.MB_TAG_SPARSE,
31
+ create_if_missing=True,
32
+ )
33
+
34
+ tags["category"] = moab_core.tag_get_handle(
35
+ types.CATEGORY_TAG_NAME,
36
+ types.CATEGORY_TAG_SIZE,
37
+ types.MB_TYPE_OPAQUE,
38
+ types.MB_TAG_SPARSE,
39
+ create_if_missing=True,
40
+ )
41
+
42
+ tags["name"] = moab_core.tag_get_handle(
43
+ types.NAME_TAG_NAME,
44
+ types.NAME_TAG_SIZE,
45
+ types.MB_TYPE_OPAQUE,
46
+ types.MB_TAG_SPARSE,
47
+ create_if_missing=True,
48
+ )
49
+
50
+ tags["geom_dimension"] = moab_core.tag_get_handle(
51
+ types.GEOM_DIMENSION_TAG_NAME,
52
+ 1,
53
+ types.MB_TYPE_INTEGER,
54
+ types.MB_TAG_DENSE,
55
+ create_if_missing=True,
56
+ )
57
+
58
+ # Global ID is a default tag, just need the name to retrieve
59
+ tags["global_id"] = moab_core.tag_get_handle(types.GLOBAL_ID_TAG_NAME)
60
+
61
+ return moab_core, tags
62
+
63
+
64
+ def _vertices_to_h5m(
65
+ vertices: typing.Union[
66
+ typing.Iterable[typing.Tuple[float, float, float]],
67
+ typing.Iterable["cadquery.occ_impl.geom.Vector"],
68
+ ],
69
+ triangles_by_solid_by_face: typing.Iterable[typing.Iterable[typing.Tuple[int, int, int]]],
70
+ material_tags: typing.Iterable[str],
71
+ h5m_filename="dagmc.h5m",
72
+ implicit_complement_material_tag=None,
73
+ ):
74
+ """Converts vertices and triangle sets into a tagged h5m file compatible
75
+ with DAGMC enabled neutronics simulations
76
+
77
+ Args:
78
+ vertices:
79
+ triangles:
80
+ material_tags:
81
+ h5m_filename:
82
+ """
83
+
84
+ if len(material_tags) != len(triangles_by_solid_by_face):
85
+ 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"
86
+ raise ValueError(msg)
87
+
88
+ # limited attribute checking to see if user passed in a list of CadQuery vectors
89
+ if hasattr(vertices[0], "x") and hasattr(vertices[0], "y") and hasattr(vertices[0], "z"):
90
+ vertices_floats = []
91
+ for vert in vertices:
92
+ vertices_floats.append((vert.x, vert.y, vert.z))
93
+ else:
94
+ vertices_floats = vertices
95
+
96
+ face_ids_with_solid_ids = {}
97
+ for solid_id, triangles_on_each_face in triangles_by_solid_by_face.items():
98
+ for face_id, triangles_on_face in triangles_on_each_face.items():
99
+ if face_id in face_ids_with_solid_ids.keys():
100
+ face_ids_with_solid_ids[face_id].append(solid_id)
101
+ else:
102
+ face_ids_with_solid_ids[face_id] = [solid_id]
103
+
104
+ moab_core, tags = _define_moab_core_and_tags()
105
+
106
+ volume_sets_by_solid_id = {}
107
+ for material_tag, (solid_id, triangles_on_each_face) in zip(
108
+ material_tags, triangles_by_solid_by_face.items()
109
+ ):
110
+ volume_set = moab_core.create_meshset()
111
+ volume_sets_by_solid_id[solid_id] = volume_set
3
112
 
4
- # from cadquery import Assembly
5
- # from OCP.GCPnts import GCPnts_QuasiUniformDeflection
113
+ added_surfaces_ids = {}
114
+ for material_tag, (solid_id, triangles_on_each_face) in zip(
115
+ material_tags, triangles_by_solid_by_face.items()
116
+ ):
117
+ volume_set = volume_sets_by_solid_id[solid_id]
6
118
 
7
- # from cadquery.occ_impl import shapes
8
- import OCP
9
- import cadquery as cq
119
+ moab_core.tag_set_data(tags["global_id"], volume_set, solid_id)
120
+ moab_core.tag_set_data(tags["geom_dimension"], volume_set, 3)
121
+ moab_core.tag_set_data(tags["category"], volume_set, "Volume")
122
+
123
+ group_set = moab_core.create_meshset()
124
+ moab_core.tag_set_data(tags["category"], group_set, "Group")
125
+ moab_core.tag_set_data(tags["name"], group_set, f"mat:{material_tag}")
126
+ moab_core.tag_set_data(tags["global_id"], group_set, solid_id)
127
+ # moab_core.tag_set_data(tags["geom_dimension"], group_set, 4)
128
+
129
+ for face_id, triangles_on_face in triangles_on_each_face.items():
130
+ if face_id not in added_surfaces_ids.keys():
131
+ face_set = moab_core.create_meshset()
132
+ moab_core.tag_set_data(tags["global_id"], face_set, face_id)
133
+ moab_core.tag_set_data(tags["geom_dimension"], face_set, 2)
134
+ moab_core.tag_set_data(tags["category"], face_set, "Surface")
135
+
136
+ if len(face_ids_with_solid_ids[face_id]) == 2:
137
+ other_solid_id = face_ids_with_solid_ids[face_id][1]
138
+ other_volume_set = volume_sets_by_solid_id[other_solid_id]
139
+ sense_data = np.array([other_volume_set, volume_set], dtype="uint64")
140
+ else:
141
+ sense_data = np.array([volume_set, 0], dtype="uint64")
142
+
143
+ moab_core.tag_set_data(tags["surf_sense"], face_set, sense_data)
144
+
145
+ moab_verts = moab_core.create_vertices(vertices)
146
+ moab_core.add_entity(face_set, moab_verts)
147
+
148
+ for triangle in triangles_on_face:
149
+ tri = (
150
+ moab_verts[int(triangle[0])],
151
+ moab_verts[int(triangle[1])],
152
+ moab_verts[int(triangle[2])],
153
+ )
154
+
155
+ moab_triangle = moab_core.create_element(types.MBTRI, tri)
156
+ moab_core.add_entity(face_set, moab_triangle)
10
157
 
11
- # from OCP.TopLoc import TopLoc_Location
12
- # from OCP.BRep import BRep_Tool
13
- # from OCP.TopAbs import TopAbs_Orientation
158
+ added_surfaces_ids[face_id] = face_set
159
+ else:
160
+ face_set = added_surfaces_ids[face_id]
14
161
 
15
- from .brep_to_h5m import mesh_brep, mesh_to_h5m_in_memory_method
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
- )
162
+ other_solid_id = face_ids_with_solid_ids[face_id][0]
163
+
164
+ other_volume_set = volume_sets_by_solid_id[other_solid_id]
165
+
166
+ sense_data = np.array([other_volume_set, volume_set], dtype="uint64")
167
+ moab_core.tag_set_data(tags["surf_sense"], face_set, sense_data)
168
+
169
+ moab_core.add_parent_child(volume_set, face_set)
170
+
171
+ moab_core.add_entity(group_set, volume_set)
172
+
173
+ if implicit_complement_material_tag:
174
+ group_set = moab_core.create_meshset()
175
+ moab_core.tag_set_data(tags["category"], group_set, "Group")
176
+ moab_core.tag_set_data(
177
+ tags["name"], group_set, f"mat:{implicit_complement_material_tag}_comp"
178
+ )
179
+ moab_core.tag_set_data(tags["geom_dimension"], group_set, 4)
180
+ moab_core.add_entity(
181
+ group_set, volume_set
182
+ ) # volume is arbitrary but should exist in moab core
183
+
184
+ all_sets = moab_core.get_entities_by_handle(0)
185
+
186
+ file_set = moab_core.create_meshset()
187
+
188
+ moab_core.add_entities(file_set, all_sets)
189
+
190
+ moab_core.write_file(h5m_filename)
191
+
192
+ return h5m_filename
193
+
194
+
195
+ def _mesh_brep(
196
+ brep_object: str,
197
+ min_mesh_size: float = 1,
198
+ max_mesh_size: float = 10,
199
+ mesh_algorithm: int = 1,
200
+ dimensions: int = 2,
201
+ ):
202
+ """Creates a conformal surface meshes of the volumes in a Brep file using
203
+ Gmsh.
204
+
205
+ Args:
206
+ brep_object: the filename of the Brep file to convert
207
+ min_mesh_size: the minimum mesh element size to use in Gmsh. Passed
208
+ into gmsh.option.setNumber("Mesh.MeshSizeMin", min_mesh_size)
209
+ max_mesh_size: the maximum mesh element size to use in Gmsh. Passed
210
+ into gmsh.option.setNumber("Mesh.MeshSizeMax", max_mesh_size)
211
+ mesh_algorithm: The Gmsh mesh algorithm number to use. Passed into
212
+ gmsh.option.setNumber("Mesh.Algorithm", mesh_algorithm)
213
+ dimensions: The number of dimensions, 2 for a surface mesh 3 for a
214
+ volume mesh. Passed to gmsh.model.mesh.generate()
215
+
216
+ Returns:
217
+ The resulting gmsh object and volumes
218
+ """
219
+
220
+ gmsh.initialize()
221
+ gmsh.option.setNumber("General.Terminal", 1)
222
+ gmsh.model.add("made_with_cad_to_dagmc_package")
223
+ volumes = gmsh.model.occ.importShapesNativePointer(brep_object)
224
+ gmsh.model.occ.synchronize()
225
+
226
+ gmsh.option.setNumber("Mesh.Algorithm", mesh_algorithm)
227
+ gmsh.option.setNumber("Mesh.MeshSizeMin", min_mesh_size)
228
+ gmsh.option.setNumber("Mesh.MeshSizeMax", max_mesh_size)
229
+ gmsh.model.mesh.generate(dimensions)
230
+
231
+ return gmsh, volumes
232
+
233
+
234
+ def _mesh_to_h5m_in_memory_method(
235
+ volumes,
236
+ ) -> str:
237
+ """Converts gmsh volumes into a DAGMC h5m file.
238
+
239
+ Args:
240
+ volumes: the volumes in the gmsh file, found with gmsh.model.occ.importShapes
241
+ material_tags: A list of material tags to tag the DAGMC volumes with.
242
+ Should be in the same order as the volumes
243
+ h5m_filename: the filename of the DAGMC h5m file to write
244
+
245
+ Returns:
246
+ vertices and triangles (grouped by solid then by face)
247
+ """
248
+
249
+ n = 3 # number of verts in a triangles
250
+ triangles_by_solid_by_face = {}
251
+ for dim_and_vol in volumes:
252
+ # removes all groups so that the following getEntitiesForPhysicalGroup
253
+ # command only finds surfaces for the volume
254
+ gmsh.model.removePhysicalGroups()
255
+
256
+ vol_id = dim_and_vol[1]
257
+ entities_in_volume = gmsh.model.getAdjacencies(3, vol_id)
258
+ surfaces_in_volume = entities_in_volume[1]
259
+ ps = gmsh.model.addPhysicalGroup(2, surfaces_in_volume)
260
+ gmsh.model.setPhysicalName(2, ps, f"surfaces_on_volume_{vol_id}")
261
+
262
+ groups = gmsh.model.getPhysicalGroups()
263
+ group = groups[0]
264
+ # for group in groups:
265
+ dim = group[0]
266
+ tag = group[1]
267
+
268
+ surfaces = gmsh.model.getEntitiesForPhysicalGroup(dim, tag)
269
+
270
+ # nodes_in_all_surfaces = []
271
+ nodes_in_each_surface = {}
272
+ for surface in surfaces:
273
+ _, _, nodeTags = gmsh.model.mesh.getElements(2, surface)
274
+ nodeTags = nodeTags[0].tolist()
275
+ shifted_node_tags = []
276
+ for nodeTag in nodeTags:
277
+ shifted_node_tags.append(nodeTag - 1)
278
+ grouped_node_tags = [
279
+ shifted_node_tags[i : i + n] for i in range(0, len(shifted_node_tags), n)
280
+ ]
281
+ nodes_in_each_surface[surface] = grouped_node_tags
282
+ triangles_by_solid_by_face[vol_id] = nodes_in_each_surface
283
+
284
+ _, all_coords, _ = gmsh.model.mesh.getNodes()
285
+
286
+ vertices = [all_coords[i : i + n].tolist() for i in range(0, len(all_coords), n)]
287
+
288
+ return vertices, triangles_by_solid_by_face
289
+
290
+
291
+ def _get_ids_from_assembly(assembly: cq.assembly.Assembly):
292
+ ids = []
293
+ for obj, name, loc, _ in assembly:
294
+ ids.append(name)
295
+ return ids
296
+
297
+
298
+ def _get_ids_from_imprinted_assembly(solid_id_dict):
299
+ ids = []
300
+ for id in list(solid_id_dict.values()):
301
+ ids.append(id[0])
302
+ return ids
303
+
304
+
305
+ def order_material_ids_by_brep_order(original_ids, scrambled_id, material_tags):
306
+ material_tags_in_brep_order = []
307
+ for brep_id in scrambled_id:
308
+ id_of_solid_in_org = original_ids.index(brep_id)
309
+ material_tags_in_brep_order.append(material_tags[id_of_solid_in_org])
310
+ return material_tags_in_brep_order
21
311
 
22
312
 
23
313
  class CadToDagmc:
24
314
  def __init__(self):
25
315
  self.parts = []
26
- self.material_tags = []
27
316
 
28
317
  def add_stp_file(
29
318
  self,
30
319
  filename: str,
31
- material_tags: typing.Iterable[str],
32
320
  scale_factor: float = 1.0,
33
321
  ):
34
- """Loads the parts from stp file into the model keeping track of the
35
- parts and their material tags.
322
+ """Loads the parts from stp file into the model.
36
323
 
37
324
  Args:
38
325
  filename: the filename used to save the html graph.
@@ -47,28 +334,22 @@ class CadToDagmc:
47
334
  """
48
335
  part = importers.importStep(str(filename)).val()
49
336
 
50
- if scale_factor == 1:
337
+ if scale_factor == 1.0:
51
338
  scaled_part = part
52
339
  else:
53
340
  scaled_part = part.scale(scale_factor)
54
- self.add_cadquery_object(object=scaled_part, material_tags=material_tags)
341
+ self.add_cadquery_object(object=scaled_part)
55
342
 
56
343
  def add_cadquery_object(
57
344
  self,
58
345
  object: typing.Union[
59
346
  cq.assembly.Assembly, cq.occ_impl.shapes.Compound, cq.occ_impl.shapes.Solid
60
347
  ],
61
- material_tags: typing.Iterable[str],
62
348
  ):
63
- """Loads the parts from CadQuery object into the model keeping track of
64
- the parts and their material tags.
349
+ """Loads the parts from CadQuery object into the model.
65
350
 
66
351
  Args:
67
352
  object: the cadquery object to convert
68
- material_tags: the names of the DAGMC material tags to assign.
69
- These will need to be in the same order as the volumes in the
70
- STP file and match the material tags used in the neutronics
71
- code (e.g. OpenMC).
72
353
  """
73
354
 
74
355
  if isinstance(object, cq.assembly.Assembly):
@@ -80,92 +361,143 @@ class CadToDagmc:
80
361
  iterable_solids = object.val().Solids()
81
362
  self.parts = self.parts + iterable_solids
82
363
 
83
- if len(iterable_solids) != len(material_tags):
84
- msg = f"Number of volumes {len(iterable_solids)} is not equal to number of material tags {len(material_tags)}"
85
- raise ValueError(msg)
86
-
87
- for material_tag in material_tags:
88
- self.material_tags.append(material_tag)
89
-
90
- def export_dagmc_h5m_file(
364
+ def export_unstructured_mesh_file(
91
365
  self,
92
- filename: str = "dagmc.h5m",
366
+ filename: str = "umesh.h5m",
93
367
  min_mesh_size: float = 1,
94
368
  max_mesh_size: float = 5,
95
369
  mesh_algorithm: int = 1,
96
- msh_filename: str = None,
97
370
  ):
371
+
98
372
  assembly = cq.Assembly()
99
373
  for part in self.parts:
100
374
  assembly.add(part)
101
375
 
102
- (
103
- imprinted_assembly,
104
- imprinted_solids_with_original_id,
105
- ) = cq.occ_impl.assembly.imprint(assembly)
376
+ imprinted_assembly, _ = cq.occ_impl.assembly.imprint(assembly)
106
377
 
107
- original_ids = get_ids_from_assembly(assembly)
108
- scrambled_ids = get_ids_from_imprinted_assembly(
109
- imprinted_solids_with_original_id
378
+ gmsh, volumes = _mesh_brep(
379
+ brep_object=imprinted_assembly.wrapped._address(),
380
+ min_mesh_size=min_mesh_size,
381
+ max_mesh_size=max_mesh_size,
382
+ mesh_algorithm=mesh_algorithm,
383
+ dimensions=3,
110
384
  )
111
385
 
112
- # both id lists should be the same length as each other and the same
113
- # length as the self.material_tags
386
+ # gmesh writes out a vtk file that is converted by pymoab into a h5 file
387
+ gmsh.write(filename + ".vtk")
114
388
 
115
- material_tags_in_brep_order = order_material_ids_by_brep_order(
116
- original_ids, scrambled_ids, self.material_tags
117
- )
389
+ moab_core = core.Core()
390
+ moab_core.load_file(filename + ".vtk")
391
+ moab_core.write_file(filename)
392
+
393
+ gmsh.finalize()
394
+
395
+ def export_gmsh_mesh_file(
396
+ self,
397
+ filename: str = "mesh.msh",
398
+ min_mesh_size: float = 1,
399
+ max_mesh_size: float = 5,
400
+ mesh_algorithm: int = 1,
401
+ dimensions: int = 2,
402
+ ):
403
+ """Saves a GMesh msh file of the geometry in either 2D surface mesh or
404
+ 3D volume mesh.
405
+
406
+ Args:
407
+ filename
408
+ min_mesh_size: the minimum size of mesh elements to use.
409
+ max_mesh_size: the maximum size of mesh elements to use.
410
+ mesh_algorithm: the gmsh mesh algorithm to use.
411
+ dimensions: The number of dimensions, 2 for a surface mesh 3 for a
412
+ volume mesh. Passed to gmsh.model.mesh.generate()
413
+ """
414
+
415
+ assembly = cq.Assembly()
416
+ for part in self.parts:
417
+ assembly.add(part)
418
+
419
+ imprinted_assembly, _ = cq.occ_impl.assembly.imprint(assembly)
118
420
 
119
- gmsh, volumes = mesh_brep(
421
+ gmsh, volumes = _mesh_brep(
120
422
  brep_object=imprinted_assembly.wrapped._address(),
121
423
  min_mesh_size=min_mesh_size,
122
424
  max_mesh_size=max_mesh_size,
123
425
  mesh_algorithm=mesh_algorithm,
426
+ dimensions=dimensions,
124
427
  )
125
428
 
126
- h5m_filename = mesh_to_h5m_in_memory_method(
127
- volumes=volumes,
128
- material_tags=material_tags_in_brep_order,
129
- h5m_filename=filename,
130
- msh_filename=msh_filename,
131
- )
132
- return h5m_filename
429
+ gmsh.write(filename)
133
430
 
431
+ gmsh.finalize()
134
432
 
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"""
433
+ def export_dagmc_h5m_file(
434
+ self,
435
+ material_tags: typing.Iterable[str],
436
+ filename: str = "dagmc.h5m",
437
+ min_mesh_size: float = 1,
438
+ max_mesh_size: float = 5,
439
+ mesh_algorithm: int = 1,
440
+ implicit_complement_material_tag: typing.Optional[str] = None,
441
+ ):
442
+ """Saves a DAGMC h5m file of the geometry
139
443
 
140
- # solids = geometry.Solids()
444
+ Args:
445
+ filename
446
+ min_mesh_size: the minimum size of mesh elements to use.
447
+ max_mesh_size: the maximum size of mesh elements to use.
448
+ mesh_algorithm: the gmsh mesh algorithm to use.
449
+ material_tags: the names of the DAGMC material tags to assign.
450
+ These will need to be in the same order as the volumes in the
451
+ geometry geometry added (STP file and CadQuery objects) and
452
+ match the material tags used in the neutronics code (e.g. OpenMC).
453
+ implicit_complement_material_tag: the name of the material tag to
454
+ use for the implicit complement (void space). Defaults to None
455
+ which is a vacuum.
456
+ """
457
+ assembly = cq.Assembly()
458
+ for part in self.parts:
459
+ assembly.add(part)
141
460
 
142
- bldr = OCP.BOPAlgo.BOPAlgo_Splitter()
461
+ imprinted_assembly, imprinted_solids_with_org_id = cq.occ_impl.assembly.imprint(assembly)
143
462
 
144
- if len(parts) == 1:
145
- # merged_solid = cq.Compound(solids)
463
+ original_ids = _get_ids_from_assembly(assembly)
464
+ scrambled_ids = _get_ids_from_imprinted_assembly(imprinted_solids_with_org_id)
146
465
 
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()
466
+ # both id lists should be the same length as each other and the same
467
+ # length as the self.material_tags
154
468
 
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)
469
+ if len(original_ids) != len(material_tags):
470
+ msg = f"Number of volumes {len(original_ids)} is not equal to number of material tags {len(material_tags)}"
471
+ raise ValueError(msg)
472
+
473
+ material_tags_in_brep_order = order_material_ids_by_brep_order(
474
+ original_ids, scrambled_ids, material_tags
475
+ )
162
476
 
163
- bldr.SetNonDestructive(True)
477
+ gmsh, volumes = _mesh_brep(
478
+ brep_object=imprinted_assembly.wrapped._address(), # in memory address
479
+ min_mesh_size=min_mesh_size,
480
+ max_mesh_size=max_mesh_size,
481
+ mesh_algorithm=mesh_algorithm,
482
+ )
164
483
 
165
- bldr.Perform()
484
+ if isinstance(material_tags_in_brep_order, str):
485
+ msg = f"material_tags should be a list of strings, not a single string."
486
+ raise ValueError(msg)
166
487
 
167
- bldr.Images()
488
+ if len(volumes) != len(material_tags_in_brep_order):
489
+ msg = f"{len(volumes)} volumes found in Brep file is not equal to the number of material_tags {len(material_tags_in_brep_order)} provided."
490
+ raise ValueError(msg)
491
+
492
+ vertices, triangles_by_solid_by_face = _mesh_to_h5m_in_memory_method(volumes=volumes)
168
493
 
169
- merged_solid = cq.Compound(bldr.Shape())
494
+ gmsh.finalize()
170
495
 
171
- return merged_solid, merged_solid.wrapped
496
+ # checks and fixes triangle fix_normals within vertices_to_h5m
497
+ return _vertices_to_h5m(
498
+ vertices=vertices,
499
+ triangles_by_solid_by_face=triangles_by_solid_by_face,
500
+ material_tags=material_tags_in_brep_order,
501
+ h5m_filename=filename,
502
+ implicit_complement_material_tag=implicit_complement_material_tag,
503
+ )
@@ -0,0 +1,144 @@
1
+ Metadata-Version: 2.1
2
+ Name: cad_to_dagmc
3
+ Version: 0.6.0
4
+ Summary: Converts CAD files to a DAGMC h5m file
5
+ Author-email: Jonathan Shimwell <mail@jshimwell.com>
6
+ Project-URL: Homepage, https://github.com/fusion-energy/cad_to_dagmc
7
+ Project-URL: Bug Tracker, https://github.com/fusion-energy/cad_to_dagmc/issues
8
+ Keywords: dagmc,geometry,plot,slice
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: License :: OSI Approved :: MIT License
11
+ Classifier: Operating System :: OS Independent
12
+ Requires-Python: >=3.8
13
+ Description-Content-Type: text/markdown
14
+ License-File: LICENSE
15
+ Requires-Dist: trimesh
16
+ Requires-Dist: networkx
17
+ Provides-Extra: tests
18
+ Requires-Dist: pytest ; extra == 'tests'
19
+ Requires-Dist: vtk ; extra == 'tests'
20
+
21
+
22
+ [![N|Python](https://www.python.org/static/community_logos/python-powered-w-100x40.png)](https://www.python.org)
23
+
24
+ [![CI with install](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/ci_with_install.yml/badge.svg?branch=main)](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/ci_with_install.yml) Testing package and running examples
25
+
26
+ [![CI with model benchmark zoo](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/ci_with_benchmarks.yml/badge.svg?branch=main)](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)
27
+
28
+ [![Upload Python Package](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/python-publish.yml/badge.svg)](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/python-publish.yml)
29
+
30
+ [![PyPI](https://img.shields.io/pypi/v/cad_to_dagmc?color=brightgreen&label=pypi&logo=grebrightgreenen&logoColor=green)](https://pypi.org/project/cad_to_dagmc/)
31
+
32
+
33
+ A minimal package that converts CAD geometry to [DAGMC](https://github.com/svalinn/DAGMC/) h5m files
34
+
35
+ cad-to-dagmc can create:
36
+ - surface meshes / faceted geometry / triangular meshes
37
+ - unstructured mesh / tetrahedral meshes / volume meshes
38
+
39
+ cad-to-dagmc can convert:
40
+ - STEP files
41
+ - CadQuery objects (in memory)
42
+
43
+ cadto-dagmc aims to produce DAGMC compatible h5m files from CAD geometry is intended to convert [STEP](http://www.steptools.com/stds/step/) files or [CadQuery](https://cadquery.readthedocs.io) objects to a [DAGMC](https://github.com/svalinn/DAGMC/) compatible h5m file.
44
+
45
+
46
+ 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/).
47
+
48
+ 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.
49
+
50
+ Also checkout these other software projects that also create DAGMC geometry [CAD-to-OpenMC](https://github.com/openmsr/CAD_to_OpenMC), [Stellarmesh](https://github.com/Thea-Energy/stellarmesh) and [Coreform Cubit](https://coreform.com/products/coreform-cubit/)
51
+
52
+ # Installation prerequisite
53
+
54
+ In principle, any Conda/Mamba distribution will work. A few Conda/Mamba options are:
55
+ - [Miniforge](https://github.com/conda-forge/miniforge) (recommended as it includes mamba)
56
+ - [Anaconda](https://www.anaconda.com/download)
57
+ - [Miniconda](https://docs.conda.io/en/latest/miniconda.html)
58
+
59
+
60
+ # Install using Mamba and pip
61
+
62
+ This example assumes you have installed the Miniforge option or separately have installed Mamba with ```conda install -c conda-forge mamba -y```
63
+
64
+ Create a new conda environment, I've chosen Python 3.10 here but newer versions are
65
+ also supported.
66
+ ```bash
67
+ mamba create --name new_env python=3.10 -y
68
+ ```
69
+
70
+ Activate the environment
71
+ ```bash
72
+ mamba activate new_env
73
+ ```
74
+
75
+ Install the dependencies
76
+ ```bash
77
+ mamba install -y -c conda-forge gmsh python-gmsh moab>=5.3.0 ocp>=7.7.2.0 cadquery>=2.4.0
78
+ ```
79
+
80
+ Then you can install the cad_to_dagmc package with ```pip```
81
+ ```bash
82
+ pip install cad_to_dagmc
83
+ ```
84
+
85
+ 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/).
86
+
87
+ To install OpenMC You can run ```mamba 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
88
+ ```bash
89
+ mamba install -c conda-forge -y "openmc=0.14.0=dagmc*nompi*"
90
+ ```
91
+
92
+ It might not be possible to install OpenMC and cad-to-dagmc in the same conda/mamba python environment so you may have to create a new conda/mamba environment and install OpenMC there.
93
+
94
+ Another option would be to [install OpenMC from source](https://docs.openmc.org/en/stable/quickinstall.html) which would also need compiling with MOAB and DAGMC options.
95
+
96
+
97
+ # Install using Conda and pip
98
+
99
+ This example uses Conda to install some dependencies that are not available via PyPi.
100
+
101
+ Create a new conda environment
102
+ ```bash
103
+ conda create --name new_env python=3.10 -y
104
+ ```
105
+
106
+ Activate the environment
107
+ ```bash
108
+ conda activate new_env
109
+ ```
110
+
111
+ Install the dependencies
112
+ ```bash
113
+ conda install -y -c conda-forge gmsh python-gmsh moab>=5.3.0 ocp>=7.7.2.0 cadquery>=2.4.0
114
+ ```
115
+
116
+ Then you can install the cad_to_dagmc package with ```pip```
117
+ ```bash
118
+ pip install cad_to_dagmc
119
+ ```
120
+
121
+ # Usage - with OpenMC
122
+
123
+ 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 supported by [DAGMC](https://svalinn.github.io/DAGMC/).
124
+
125
+ You can run ```mamba install -c conda-forge openmc``` however this may choose to install OpenMC without DAGMC included.
126
+
127
+ You can be more specific with conda/mamba commands to make sure the latest version of OpenMC which contains DAGMC is chosen by conda / mamba
128
+ ```bash
129
+ mamba install -c conda-forge -y "openmc=0.14.0=dagmc*nompi*"
130
+ ```
131
+
132
+ You could also [install OpenMC from source](https://docs.openmc.org/en/stable/quickinstall.html) which might be prefered as it can be tricky for the conda enviroment to get resolved.
133
+
134
+
135
+
136
+ # Usage - creation of DAGMC h5m files
137
+
138
+ For examples see the [examples folder](https://github.com/fusion-energy/cad_to_dagmc/tree/main/examples)
139
+
140
+ # Usage - simulation with transport code
141
+
142
+ For examples see the [examples folder](https://github.com/fusion-energy/cad_to_dagmc/tree/main/examples)
143
+
144
+ For more examples see the CAD tasks in the [neutronics-workshop](https://github.com/fusion-energy/neutronics-workshop) and [model benchmark zoo](https://github.com/fusion-energy/model_benchmark_zoo)
@@ -0,0 +1,8 @@
1
+ _version.py,sha256=2JKwcA-YQ0okV2N-gwTWy_n51igWrPcsKQFm0cnqsvw,411
2
+ cad_to_dagmc/__init__.py,sha256=fskHUTyCunSpnpJUvBfAYjx4uwDKXHTTiMP6GqnFRf0,494
3
+ cad_to_dagmc/core.py,sha256=eMwKgKOjje3gBZEqjNzy9O6NF8a02WxD-VhXB5AJg58,18108
4
+ cad_to_dagmc-0.6.0.dist-info/LICENSE,sha256=B8kznH_777JVNZ3HOKDc4Tj24F7wJ68ledaNYeL9sCw,1070
5
+ cad_to_dagmc-0.6.0.dist-info/METADATA,sha256=Zrz_-X2KkLAoKrucNIcvOr1070dmSxq10ytsfqU5oWA,6771
6
+ cad_to_dagmc-0.6.0.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
7
+ cad_to_dagmc-0.6.0.dist-info/top_level.txt,sha256=zTi8C64SEBsE5WOtPovnxhOzt-E6Oc5nC3RW6M_5aEA,22
8
+ cad_to_dagmc-0.6.0.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: bdist_wheel (0.41.2)
2
+ Generator: bdist_wheel (0.43.0)
3
3
  Root-Is-Purelib: true
4
4
  Tag: py3-none-any
5
5
 
@@ -1,36 +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
- ids.append(id[0])
28
- return ids
29
-
30
-
31
- def order_material_ids_by_brep_order(original_ids, scrambled_id, material_tags):
32
- material_tags_in_brep_order = []
33
- for brep_id in scrambled_id:
34
- id_of_solid_in_org = original_ids.index(brep_id)
35
- material_tags_in_brep_order.append(material_tags[id_of_solid_in_org])
36
- return material_tags_in_brep_order
@@ -1,121 +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 = 1,
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
- msh_filename=None,
49
- ) -> str:
50
- """Converts gmsh volumes into a DAGMC h5m file.
51
-
52
- Args:
53
- volumes: the volumes in the gmsh file, found with gmsh.model.occ.importShapes
54
- material_tags: A list of material tags to tag the DAGMC volumes with.
55
- Should be in the same order as the volumes
56
- h5m_filename: the filename of the DAGMC h5m file to write
57
-
58
- Returns:
59
- The filename of the h5m file produced
60
- """
61
-
62
- if isinstance(material_tags, str):
63
- msg = f"material_tags should be a list of strings, not a single string."
64
- raise ValueError(msg)
65
-
66
- if len(volumes) != len(material_tags):
67
- msg = f"{len(volumes)} volumes found in Brep file is not equal to the number of material_tags {len(material_tags)} provided."
68
- raise ValueError(msg)
69
-
70
- n = 3 # number of verts in a triangles
71
- triangles_by_solid_by_face = {}
72
- for dim_and_vol in volumes:
73
- # removes all groups so that the following getEntitiesForPhysicalGroup
74
- # command only finds surfaces for the volume
75
- gmsh.model.removePhysicalGroups()
76
-
77
- vol_id = dim_and_vol[1]
78
- entities_in_volume = gmsh.model.getAdjacencies(3, vol_id)
79
- surfaces_in_volume = entities_in_volume[1]
80
- ps = gmsh.model.addPhysicalGroup(2, surfaces_in_volume)
81
- gmsh.model.setPhysicalName(2, ps, f"surfaces_on_volume_{vol_id}")
82
-
83
- groups = gmsh.model.getPhysicalGroups()
84
- group = groups[0]
85
- # for group in groups:
86
- dim = group[0]
87
- tag = group[1]
88
-
89
- surfaces = gmsh.model.getEntitiesForPhysicalGroup(dim, tag)
90
-
91
- # nodes_in_all_surfaces = []
92
- nodes_in_each_surface = {}
93
- for surface in surfaces:
94
- _, _, nodeTags = gmsh.model.mesh.getElements(2, surface)
95
- nodeTags = nodeTags[0].tolist()
96
- shifted_node_tags = []
97
- for nodeTag in nodeTags:
98
- shifted_node_tags.append(nodeTag - 1)
99
- grouped_node_tags = [
100
- shifted_node_tags[i : i + n]
101
- for i in range(0, len(shifted_node_tags), n)
102
- ]
103
- nodes_in_each_surface[surface] = grouped_node_tags
104
- triangles_by_solid_by_face[vol_id] = nodes_in_each_surface
105
-
106
- _, all_coords, _ = gmsh.model.mesh.getNodes()
107
-
108
- vertices = [all_coords[i : i + n].tolist() for i in range(0, len(all_coords), n)]
109
-
110
- if msh_filename is not None:
111
- gmsh.write(msh_filename)
112
-
113
- gmsh.finalize()
114
-
115
- # checks and fixes triangle fix_normals within vertices_to_h5m
116
- return vertices_to_h5m(
117
- vertices=vertices,
118
- triangles_by_solid_by_face=triangles_by_solid_by_face,
119
- material_tags=material_tags,
120
- h5m_filename=h5m_filename,
121
- )
@@ -1,262 +0,0 @@
1
- from typing import Iterable, Tuple, Union
2
- import typing
3
- import numpy as np
4
- import trimesh
5
- from pymoab import core, types
6
-
7
-
8
- def fix_normals(vertices: list, triangles_in_each_volume: list):
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: list, triangles: list):
16
- mesh = trimesh.Trimesh(vertices=vertices, faces=triangles, process=False)
17
-
18
- mesh.fix_normals()
19
-
20
- return mesh.faces
21
-
22
-
23
- def _define_moab_core_and_tags() -> Tuple[core.Core, dict]:
24
- """Creates a MOAB Core instance which can be built up by adding sets of
25
- triangles to the instance
26
-
27
- Returns:
28
- (pymoab Core): A pymoab.core.Core() instance
29
- (pymoab tag_handle): A pymoab.core.tag_get_handle() instance
30
- """
31
-
32
- # create pymoab instance
33
- moab_core = core.Core()
34
-
35
- tags = dict()
36
-
37
- sense_tag_name = "GEOM_SENSE_2"
38
- sense_tag_size = 2
39
- tags["surf_sense"] = moab_core.tag_get_handle(
40
- sense_tag_name,
41
- sense_tag_size,
42
- types.MB_TYPE_HANDLE,
43
- types.MB_TAG_SPARSE,
44
- create_if_missing=True,
45
- )
46
-
47
- tags["category"] = moab_core.tag_get_handle(
48
- types.CATEGORY_TAG_NAME,
49
- types.CATEGORY_TAG_SIZE,
50
- types.MB_TYPE_OPAQUE,
51
- types.MB_TAG_SPARSE,
52
- create_if_missing=True,
53
- )
54
-
55
- tags["name"] = moab_core.tag_get_handle(
56
- types.NAME_TAG_NAME,
57
- types.NAME_TAG_SIZE,
58
- types.MB_TYPE_OPAQUE,
59
- types.MB_TAG_SPARSE,
60
- create_if_missing=True,
61
- )
62
-
63
- tags["geom_dimension"] = moab_core.tag_get_handle(
64
- types.GEOM_DIMENSION_TAG_NAME,
65
- 1,
66
- types.MB_TYPE_INTEGER,
67
- types.MB_TAG_DENSE,
68
- create_if_missing=True,
69
- )
70
-
71
- # Global ID is a default tag, just need the name to retrieve
72
- tags["global_id"] = moab_core.tag_get_handle(types.GLOBAL_ID_TAG_NAME)
73
-
74
- return moab_core, tags
75
-
76
-
77
- def prepare_moab_core_volume_set(
78
- moab_core,
79
- volume_id,
80
- tags,
81
- ):
82
- volume_set = moab_core.create_meshset()
83
-
84
- # recent versions of MOAB handle this automatically
85
- # but best to go ahead and do it manually
86
- moab_core.tag_set_data(tags["global_id"], volume_set, volume_id)
87
-
88
- # set geom IDs
89
- moab_core.tag_set_data(tags["geom_dimension"], volume_set, 3)
90
-
91
- # set category tag values
92
- moab_core.tag_set_data(tags["category"], volume_set, "Volume")
93
-
94
- return moab_core, volume_set
95
-
96
-
97
- def prepare_moab_core_surface_set(
98
- moab_core,
99
- surface_id,
100
- tags,
101
- ):
102
- surface_set = moab_core.create_meshset()
103
-
104
- moab_core.tag_set_data(tags["global_id"], surface_set, surface_id)
105
-
106
- # set geom IDs
107
- moab_core.tag_set_data(tags["geom_dimension"], surface_set, 2)
108
-
109
- # set category tag values
110
- moab_core.tag_set_data(tags["category"], surface_set, "Surface")
111
-
112
- return moab_core, surface_set
113
-
114
-
115
- def add_triangles_to_moab_core(
116
- material_tag, surface_set, moab_core, tags, triangles, moab_verts, volume_set
117
- ):
118
- for triangle in triangles:
119
- tri = (
120
- moab_verts[int(triangle[0])],
121
- moab_verts[int(triangle[1])],
122
- moab_verts[int(triangle[2])],
123
- )
124
-
125
- moab_triangle = moab_core.create_element(types.MBTRI, tri)
126
- moab_core.add_entity(surface_set, moab_triangle)
127
-
128
- group_set = moab_core.create_meshset()
129
-
130
- moab_core.tag_set_data(tags["category"], group_set, "Group")
131
-
132
- moab_core.tag_set_data(tags["name"], group_set, f"mat:{material_tag}")
133
-
134
- moab_core.tag_set_data(tags["geom_dimension"], group_set, 4)
135
-
136
- moab_core.add_entity(group_set, volume_set)
137
-
138
- return moab_core
139
-
140
-
141
- def vertices_to_h5m(
142
- vertices: Union[
143
- Iterable[Tuple[float, float, float]], Iterable["cadquery.occ_impl.geom.Vector"]
144
- ],
145
- triangles_by_solid_by_face: Iterable[Iterable[Tuple[int, int, int]]],
146
- material_tags: Iterable[str],
147
- h5m_filename="dagmc.h5m",
148
- ):
149
- """Converts vertices and triangle sets into a tagged h5m file compatible
150
- with DAGMC enabled neutronics simulations
151
-
152
- Args:
153
- vertices:
154
- triangles:
155
- material_tags:
156
- h5m_filename:
157
- """
158
-
159
- if len(material_tags) != len(triangles_by_solid_by_face):
160
- 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"
161
- raise ValueError(msg)
162
-
163
- # limited attribute checking to see if user passed in a list of CadQuery vectors
164
- if (
165
- hasattr(vertices[0], "x")
166
- and hasattr(vertices[0], "y")
167
- and hasattr(vertices[0], "z")
168
- ):
169
- vertices_floats = []
170
- for vert in vertices:
171
- vertices_floats.append((vert.x, vert.y, vert.z))
172
- else:
173
- vertices_floats = vertices
174
-
175
- face_ids_with_solid_ids = {}
176
- for solid_id, triangles_on_each_face in triangles_by_solid_by_face.items():
177
- for face_id, triangles_on_face in triangles_on_each_face.items():
178
- if face_id in face_ids_with_solid_ids.keys():
179
- face_ids_with_solid_ids[face_id].append(solid_id)
180
- else:
181
- face_ids_with_solid_ids[face_id] = [solid_id]
182
-
183
- moab_core, tags = _define_moab_core_and_tags()
184
-
185
- volume_sets_by_solid_id = {}
186
- for material_tag, (solid_id, triangles_on_each_face) in zip(
187
- material_tags, triangles_by_solid_by_face.items()
188
- ):
189
- volume_set = moab_core.create_meshset()
190
- volume_sets_by_solid_id[solid_id] = volume_set
191
-
192
- added_surfaces_ids = {}
193
- for material_tag, (solid_id, triangles_on_each_face) in zip(
194
- material_tags, triangles_by_solid_by_face.items()
195
- ):
196
- volume_set = volume_sets_by_solid_id[solid_id]
197
-
198
- moab_core.tag_set_data(tags["global_id"], volume_set, solid_id)
199
- moab_core.tag_set_data(tags["geom_dimension"], volume_set, 3)
200
- moab_core.tag_set_data(tags["category"], volume_set, "Volume")
201
-
202
- group_set = moab_core.create_meshset()
203
- moab_core.tag_set_data(tags["category"], group_set, "Group")
204
- moab_core.tag_set_data(tags["name"], group_set, f"mat:{material_tag}")
205
- moab_core.tag_set_data(tags["global_id"], group_set, solid_id)
206
- # moab_core.tag_set_data(tags["geom_dimension"], group_set, 4)
207
-
208
- for face_id, triangles_on_face in triangles_on_each_face.items():
209
- if face_id not in added_surfaces_ids.keys():
210
- face_set = moab_core.create_meshset()
211
- moab_core.tag_set_data(tags["global_id"], face_set, face_id)
212
- moab_core.tag_set_data(tags["geom_dimension"], face_set, 2)
213
- moab_core.tag_set_data(tags["category"], face_set, "Surface")
214
-
215
- if len(face_ids_with_solid_ids[face_id]) == 2:
216
- other_solid_id = face_ids_with_solid_ids[face_id][1]
217
- other_volume_set = volume_sets_by_solid_id[other_solid_id]
218
- sense_data = np.array(
219
- [other_volume_set, volume_set], dtype="uint64"
220
- )
221
- else:
222
- sense_data = np.array([volume_set, 0], dtype="uint64")
223
-
224
- moab_core.tag_set_data(tags["surf_sense"], face_set, sense_data)
225
-
226
- moab_verts = moab_core.create_vertices(vertices)
227
- moab_core.add_entity(face_set, moab_verts)
228
-
229
- for triangle in triangles_on_face:
230
- tri = (
231
- moab_verts[int(triangle[0])],
232
- moab_verts[int(triangle[1])],
233
- moab_verts[int(triangle[2])],
234
- )
235
-
236
- moab_triangle = moab_core.create_element(types.MBTRI, tri)
237
- moab_core.add_entity(face_set, moab_triangle)
238
-
239
- added_surfaces_ids[face_id] = face_set
240
- else:
241
- face_set = added_surfaces_ids[face_id]
242
-
243
- other_solid_id = face_ids_with_solid_ids[face_id][0]
244
-
245
- other_volume_set = volume_sets_by_solid_id[other_solid_id]
246
-
247
- sense_data = np.array([other_volume_set, volume_set], dtype="uint64")
248
- moab_core.tag_set_data(tags["surf_sense"], face_set, sense_data)
249
-
250
- moab_core.add_parent_child(volume_set, face_set)
251
-
252
- moab_core.add_entity(group_set, volume_set)
253
-
254
- all_sets = moab_core.get_entities_by_handle(0)
255
-
256
- file_set = moab_core.create_meshset()
257
-
258
- moab_core.add_entities(file_set, all_sets)
259
-
260
- moab_core.write_file(h5m_filename)
261
-
262
- return h5m_filename
@@ -1,119 +0,0 @@
1
- Metadata-Version: 2.1
2
- Name: cad-to-dagmc
3
- Version: 0.5.0
4
- Summary: Converts CAD files to a DAGMC h5m file
5
- Author-email: Jonathan Shimwell <mail@jshimwell.com>
6
- Project-URL: Homepage, https://github.com/fusion-energy/cad_to_dagmc
7
- Project-URL: Bug Tracker, https://github.com/fusion-energy/cad_to_dagmc/issues
8
- Keywords: dagmc,geometry,plot,slice
9
- Classifier: Programming Language :: Python :: 3
10
- Classifier: License :: OSI Approved :: MIT License
11
- Classifier: Operating System :: OS Independent
12
- Requires-Python: >=3.8
13
- Description-Content-Type: text/markdown
14
- License-File: LICENSE
15
- Requires-Dist: trimesh
16
- Requires-Dist: networkx
17
- Provides-Extra: tests
18
- Requires-Dist: pytest ; extra == 'tests'
19
-
20
-
21
- [![N|Python](https://www.python.org/static/community_logos/python-powered-w-100x40.png)](https://www.python.org)
22
-
23
- [![CI with install](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/ci_with_install.yml/badge.svg)](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/ci_with_install.yml)
24
-
25
- [![Upload Python Package](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/python-publish.yml/badge.svg)](https://github.com/fusion-energy/cad_to_dagmc/actions/workflows/python-publish.yml)
26
-
27
- [![PyPI](https://img.shields.io/pypi/v/cad_to_dagmc?color=brightgreen&label=pypi&logo=grebrightgreenen&logoColor=green)](https://pypi.org/project/cad_to_dagmc/)
28
-
29
- ___
30
-
31
- A minimal package that uses CadQuery functionality to convert CAD geometry to [DAGMC](https://github.com/svalinn/DAGMC/) h5m files
32
-
33
- This particular method of producing DAGMC compatible h5m files from CAD geometry
34
- is intended to convert STP files or [CadQuery](https://cadquery.readthedocs.io) objects to h5m file.
35
-
36
- One unique feature of this package is the ability to combine STP files with CadQuery objects.
37
- This allows for the addition of parametric geometry to static geometry.
38
-
39
- 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/).
40
-
41
- # Installation prerequisite
42
-
43
- In principle, any Conda/Mamba distribution will work. A few Conda/Mamba options are:
44
- - [Mambaforge](https://github.com/conda-forge/miniforge#mambaforge)
45
- - [Miniforge](https://github.com/conda-forge/miniforge#miniforge-pypy3)
46
- - [Anaconda](https://www.anaconda.com/download)
47
- - [Miniconda](https://docs.conda.io/en/latest/miniconda.html)
48
-
49
-
50
- # Install using Mamba and pip
51
-
52
- This example assumes you have installed the MambaForge option or separately
53
- installed Mamba with ```conda install -c conda-forge mamba -y```
54
-
55
- Create a new conda environment, I've chosen Python 3.9 here but new versions are
56
- also supported.
57
- ```bash
58
- mamba create --name new_env python=3.9 -y
59
- ```
60
-
61
- Activate the environment
62
- ```bash
63
- mamba activate new_env
64
- ```
65
-
66
- Install the dependencies
67
- ```bash
68
- mamba install -c cadquery -c conda-forge moab gmsh python-gmsh cadquery=master -y
69
- ```
70
-
71
- Then you can install the cad_to_dagmc package with ```pip```
72
- ```bash
73
- pip install cad_to_dagmc
74
- ```
75
-
76
- 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
77
- ```bash
78
- mamba install -c conda-forge -y "openmc=0.13.3=dagmc*nompi*"
79
- ```
80
-
81
-
82
- # Install using Conda and pip
83
-
84
- This example uses Conda to install some dependencies that are not available via PyPi.
85
-
86
- Create a new conda environment
87
- ```bash
88
- conda create --name new_env python=3.9 -y
89
- ```
90
-
91
- Activate the environment
92
- ```bash
93
- conda activate new_env
94
- ```
95
-
96
- Install the dependencies
97
- ```bash
98
- conda install -c cadquery -c conda-forge moab gmsh python-gmsh cadquery=master -y
99
- ```
100
-
101
- Then you can install the cad_to_dagmc package with ```pip```
102
- ```bash
103
- pip install cad_to_dagmc
104
- ```
105
-
106
- 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
107
- ```bash
108
- conda install -c conda-forge -y "openmc=0.13.3=dagmc*nompi*"
109
- ```
110
-
111
-
112
-
113
- # Usage - creation of DAGMC h5m files
114
-
115
- For examples see the [examples folder](https://github.com/fusion-energy/cad_to_dagmc/tree/main/examples)
116
-
117
- # Usage - simulation with transport code
118
-
119
- For examples see the CAD tasks in the [neutronics-workshop](https://github.com/fusion-energy/neutronics-workshop)
@@ -1,11 +0,0 @@
1
- _version.py,sha256=3YxISZVp_DgBHizWP4UzbUATbJ2-kn6oz3xEF0uxyCg,274
2
- cad_to_dagmc/__init__.py,sha256=pI6sOn4nbEiZClP53g2UJSNgE8tkm9wz-hA_JLwUkLk,638
3
- cad_to_dagmc/brep_part_finder.py,sha256=Se5IYTbPvmYOU28C-Sx2xYrn6ZRVXWicNjra1lVyWxw,999
4
- cad_to_dagmc/brep_to_h5m.py,sha256=AXm8AF68rD6iSNpLcSyGwCPTUyXC1yoLH47Q4hmUZFc,4266
5
- cad_to_dagmc/core.py,sha256=Sd2ITQfg2pEcRjpUGZgysGJNdiXrk9En953ItqgAH7o,5584
6
- cad_to_dagmc/vertices_to_h5m.py,sha256=AUi8ddOl5pv1riH7rZY4r4L1GsgoPUO_NZ4S2sxwPJQ,8550
7
- cad_to_dagmc-0.5.0.dist-info/LICENSE,sha256=B8kznH_777JVNZ3HOKDc4Tj24F7wJ68ledaNYeL9sCw,1070
8
- cad_to_dagmc-0.5.0.dist-info/METADATA,sha256=oj692qzyRJyYR13BfyZyaoJ4Ue1QMKvbRs6U2osQ19U,4838
9
- cad_to_dagmc-0.5.0.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
10
- cad_to_dagmc-0.5.0.dist-info/top_level.txt,sha256=zTi8C64SEBsE5WOtPovnxhOzt-E6Oc5nC3RW6M_5aEA,22
11
- cad_to_dagmc-0.5.0.dist-info/RECORD,,