I am using cubit 2025.8 in windows to set up a (preferably Hex) mesh for a complex geometry. I have hundreds of small surfaces/fractures in the doman which also cross-cut each other. For the mesh my first wish is to embed the fractures inside the volume. By embed I mean that the mesh in the fracture surfaces should share its nodes, edges, and surfaces with the volume. Secondly, I would like to have a bit of refinement on the surfaces. I very much appreciate any help. This is how I make the geometry in the cubit:
#!cubit
reset
#!python
import numpy as np
# Read Data from file
nested_fractures = np.load(r"...\DFN_Mesh\data\DFN_Frac_corners.npy")
for frac in range (len(nested_fractures)):
for point in nested_fractures[frac]:
cubit.cmd(f"create vertex location {point[0]} {point[1]} {point[2]}")
n_groups = len (nested_fractures) * 4
frac_ids = np.arange (1, n_groups+1).reshape(-1, 4)
for frac in frac_ids:
cubit.cmd(f"create surface vertex {frac[0]} {frac[1]} {frac[2]} {frac[3]}")
n_fracs = len (nested_fractures)
cubit.cmd ("brick x 100 y 50 z 520")
cubit.cmd (f"move Volume {n_fracs+1} z -260 include_merged")
#!cubit
imprint surface all
merge surface all
Here is a view into the geometry with 571 surfaces:
Hello Ali,
i didn’t find a way to get a hex mesh that is fitted to those surfaces.
But we could use mesh intersections to approximate those surfaces. For this we would need to sweep the fracture surfaces to get a volume. Then we can check for mesh intersections with the surrounding volume.
If your machine got a lot of resources you could use a smaller mesh size and refine more to be more accurate.
#!cubit
reset
set developer on
set fullhex on
#!python
import numpy as np
# Read Data from file
nested_fractures = np.load(r"DFN_Frac_corners.npy")
#for frac in range (len(nested_fractures)):
max_frac = 5
for frac in range (max_frac):
for point in nested_fractures[frac]:
cubit.cmd(f"create vertex location {point[0]} {point[1]} {point[2]}")
#n_groups = len (nested_fractures) * 4
n_groups = max_frac * 4
frac_ids = np.arange (1, n_groups+1).reshape(-1, 4)
for frac in frac_ids:
cubit.cmd(f"create surface vertex {frac[0]} {frac[1]} {frac[2]} {frac[3]}")
#n_fracs = len (nested_fractures)
n_fracs = max_frac
sids = cubit.parse_cubit_list("surface","all in body all with is_sheet")
for sid in sids:
cubit.cmd(f"sweep surface {sid} perpendicular distance 0.1")
cubit.cmd ("brick x 100 y 50 z 520")
cubit.cmd (f"move Volume {n_fracs+1} z -260 include_merged")
vid = cubit.get_last_id('volume')
cubit.cmd("vol all size 3")
cubit.cmd("mesh vol all")
for sid in sids:
cubit.cmd(f"find mesh intersection Volume {vid} with Volume {sid} exhaustive ")
hexes = cubit.parse_cubit_list("hex","all in group all except 1")
cubit.cmd(f"refine hex {' '.join(str(id) for id in hexes)} numsplit 1 bias 1.0 depth 0 smooth")
cubit.cmd("delete group all")
for sid in sids:
cubit.cmd(f"find mesh intersection Volume {vid} with Volume {sid} exhaustive ")
cubit.cmd("set duplicate block elements on")
gids = cubit.parse_cubit_list("group","all except 1")
i = 1
for gid in gids:
hexes = cubit.get_group_hexes(gid)
cubit.cmd(f"block {i} add hex {' '.join(str(id) for id in hexes)}")
i = i +1
#!cubit
draw block all
Thanks a lot for your solution. The mesh will be super heavy if I repeat the process for ca. 500 surfaces. Is there a simpler way to make the tet mesh for this geometry? The fracture surfaces should be embedded inside the volume.
Actually i think not.
Usually i would suggest to use tetmesh respect tri in surface but that will only work for a small number of fractures. At some point the fractures overlap to much and meshgems can’t handle it.
#!cubit
reset
#!python
import numpy as np
# Read Data from file
nested_fractures = np.load(r"\DFN_Frac_corners.npy")
#for frac in range (len(nested_fractures)):
max_frac = 10
for frac in range (max_frac):
for point in nested_fractures[frac]:
cubit.cmd(f"create vertex location {point[0]} {point[1]} {point[2]}")
#n_groups = len (nested_fractures) * 4
n_groups = max_frac * 4
frac_ids = np.arange (1, n_groups+1).reshape(-1, 4)
for frac in frac_ids:
cubit.cmd(f"create surface vertex {frac[0]} {frac[1]} {frac[2]} {frac[3]}")
#n_fracs = len (nested_fractures)
n_fracs = max_frac
cubit.cmd ("brick x 100 y 50 z 520")
cubit.cmd (f"move Volume {n_fracs+1} z -260 include_merged")
vid = cubit.get_last_id('volume')
cubit.cmd("imprint body all with is_sheet")
cubit.cmd("merge body all with is_sheet")
cubit.cmd("surface all with is_sheet scheme trimesh")
cubit.cmd("mesh surface all with is_sheet")
sids = cubit.parse_cubit_list("surface","all with is_sheet")
cubit.cmd(f"vol {vid} scheme tetmesh")
cubit.cmd(f"vol {vid} tetmesh respect tri in surface {' '.join(str(id) for id in sids)}")
cubit.cmd(f"mesh vol {vid}")