Creating consistent void mesh given material mesh

Hi all —

I’m importing an abaqus mesh from an input file for a material region. The goal is to also generate the void region defined as the material’s complement, i.e. as the region formed when the material region is subtracted from its smalles bounding box, and mesh it such that it is consistent with the material region’s mesh.

Here’s the mesh generated by the input file:

Here’s how I create the void volume(s):

  • create the bounding box for the material part
  • subtract the material part from it to form the two disconnected void volumes
  • delete the remaining bounding box and split the two disconnected void volumes

The part I’m stuck at is how to tell cubit to generate a mesh on the void volumes such that they are consistent with the mesh already existing on the material region. My main attempts involve telling cubit to mesh the void region while respecting the tri already existing on the material mesh, e.g. for volume 67 one of the void regions and surface 1 the surface on the material mesh that is in contact with volume 67,

volume 67 scheme tetmesh
volume 67 tetmesh respect tri in surface 1
mesh volume 67

but this isn’t successful. Any advice is appreciated. I’ve attached the abaqus input file and the whole journal file.

MaterialVoid.jou (1.9 KB)
TPMS 5x1x1.inp (4.9 MB)

Try this. Note that I had to “guess & check” with the Abaqus import’s feature_angle option a bit, because I noticed that the default value resulted in two “obviously unique” surfaces being recognized as a single surface - which threw-off Booleans and merging:

Default feature_angle: 135 degrees

Note the missing curve in the middle that should separate the side face and the internal face

Better feature_angle: 145 degrees

#!cubit
reset
set developer commands on
set geometry engine facet
# {NumCellsX=5}
# {NumCellsY=1}
# {NumCellsZ=1}

import abaqus mesh geometry  "TPMS 5x1x1.inp" feature_angle 145.00 

#!python
import numpy
vol_ids = cubit.get_entities( "volume" )
V = numpy.array( [cubit.get_volume_volume(vol_id) for vol_id in vol_ids] )
sidx = numpy.argsort( V )
for i in range( 0, len( sidx ) - 1 ):
  cubit.cmd( f"delete volume {int( vol_ids[sidx[i]] )}" )
cubit.cmd( f"volume all scale {2*numpy.pi}" )

#!cubit
# left,  back,  bottom,  right,  front,  top, interior surface
SideSet 1 Surface all Patch Maximum { -3.134 * NumCellsX } { 3.142 * NumCellsY } { 3.142 * NumCellsZ } Minimum { -3.206 * NumCellsX } { -3.142 * NumCellsY } { -3.142 * NumCellsZ }
SideSet 2 Surface all Patch Maximum { 3.142 * NumCellsX } { 3.142 * NumCellsY } { -3.134 * NumCellsZ } Minimum { -3.142 * NumCellsX } { -3.142 * NumCellsY } { -3.206 * NumCellsZ }
SideSet 3 Surface all Patch Maximum { 3.142 * NumCellsX } { -3.134 * NumCellsY } { 3.142 * NumCellsZ } Minimum { -3.142 * NumCellsX } { -3.206 * NumCellsY } { -3.142 * NumCellsZ }
SideSet 4 Surface all Patch Maximum { 3.206 * NumCellsX } { 3.142 * NumCellsY } { 3.142 * NumCellsZ } Minimum { 3.134 * NumCellsX } { -3.142 * NumCellsY } { -3.142 * NumCellsZ }
SideSet 5 Surface all Patch Maximum { 3.142 * NumCellsX } { 3.142 * NumCellsY } { 3.206 * NumCellsZ } Minimum { -3.142 * NumCellsX } { -3.142 * NumCellsY } { 3.134 * NumCellsZ }
SideSet 6 Surface all Patch Maximum { 3.142 * NumCellsX } { 3.206 * NumCellsY } { 3.142 * NumCellsZ } Minimum { -3.142 * NumCellsX } { 3.134 * NumCellsY } { -3.142 * NumCellsZ }
SideSet 7 Surface all Patch Maximum { 3.134 * NumCellsX } { 3.134 * NumCellsY } { 3.134 * NumCellsZ } Minimum { -3.134 * NumCellsX } { -3.134 * NumCellsY } { -3.134 * NumCellsZ }

# Create void region
#!python
## Generate bounding box manually
bbox = cubit.get_bounding_box( "volume", 1 )
cubit.cmd( f"create brick x {bbox[2]} y {bbox[5]} z {bbox[8]}" )
tool_vol_id = cubit.get_last_id( 'volume' )
### Scale the bounding box *slightly* to avoid numerical issues with Boolean
cubit.cmd( f"volume {tool_vol_id} scale {1-1e-4}" )
### Center the bounding box on the solid region
dx = ( bbox[0] + bbox[1] ) / 2.0
dy = ( bbox[3] + bbox[4] ) / 2.0
dz = ( bbox[6] + bbox[7] ) / 2.0
cubit.cmd( f"move volume {tool_vol_id} x {dx} y {dy} z {dz}" )
## Perform Boolean operation
cubit.cmd( f"subtract volume 1 from volume {tool_vol_id} keep" )
cubit.cmd( f"delete volume {tool_vol_id}" )
cubit.cmd( "split body all" )

#!cubit
# Enforce contiguous mesh
## Set a slightly looser tolerance for merging
merge tolerance 5.0e-3
merge volume all 
merge tolerance 5.0e-04

# Generate the mesh
vol all except with is_meshed scheme tetmesh
## Due to facet-meshing issues with default Trimesh scheme, use Triadvance
surf all except with is_meshed scheme triadvance
mesh surf all except with is_meshed
## Mesh the void volumes
mesh vol all except with is_meshed 

Works perfectly as described. Thanks a bunch for the insightful answer.

I’d never heard of the triadvance meshing scheme. It sounds like that, in conjunction with the feature angles and merge tolerances, was the key to getting around the issue.