Skip to content

Commit 84fc35b

Browse files
authored
Adding an mesh tools python package for GEOSX (#1224)
* Adding an mesh tools python package for GEOSX * Converting indentation to four spaces * Implementing various upgrades to the abaqus converter script * Converting print messages to logs in abaqus converter * Updating the docstring for the abaqus converter script * Moving around the logger in the abaqus converter * Updating the abaqus converter error messaging * Adding exit warning message, multi-block support to abaqus converter * Fixing a typo in the abaqus converter
1 parent b6f5527 commit 84fc35b

File tree

3 files changed

+162
-0
lines changed

3 files changed

+162
-0
lines changed

geosx_mesh_tools_package/geosx_mesh_tools/__init__.py

Whitespace-only changes.
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
2+
import meshio
3+
from meshio._mesh import CellBlock
4+
import numpy as np
5+
import argparse
6+
import logging
7+
import sys
8+
9+
10+
def convert_abaqus_to_gmsh(input_mesh, output_mesh, logger=None):
11+
"""
12+
@brief Convert an abaqus mesh to gmsh 2 format, preserving nodeset information.
13+
@details If the code encounters any issues with region/element indices,
14+
the conversion will attempt to continue, with errors
15+
indicated by -1 values in the output file.
16+
@param input_mesh path of the input abaqus file
17+
@param output_mesh path of the output gmsh file
18+
@param logger an instance of logging.Logger
19+
"""
20+
# Initialize the logger if it is empty
21+
if not logger:
22+
logging.basicConfig(level=logging.WARNING)
23+
logger = logging.getLogger(__name__)
24+
25+
# Keep track of the number of warnings
26+
n_warnings = 0
27+
28+
# Load the mesh
29+
logger.info('Reading abaqus mesh...')
30+
mesh = meshio.read(input_mesh, file_format="abaqus")
31+
32+
# Convert the element regions to tags
33+
logger.info('Converting region tags...')
34+
region_list = list(mesh.cell_sets.keys())
35+
n_regions = len(region_list)
36+
cell_ids = []
37+
for block_id, block in enumerate(mesh.cells):
38+
cell_ids.append(np.zeros(len(block[1]), dtype=int) - 1)
39+
for region_id, region in enumerate(region_list):
40+
mesh.field_data[region] = [region_id + 1, 3]
41+
cell_ids[block_id][mesh.cell_sets[region][block_id]] = region_id + 1
42+
43+
# Check for bad element region conversions
44+
if (-1 in cell_ids[-1]):
45+
logger.warning('Some element regions in block %i did not convert correctly to tags!' % (block_id))
46+
logger.warning('Note: These will be indicated by a -1 in the output file.')
47+
n_warnings += 1
48+
49+
# Add to the meshio datastructure
50+
# Note: the copy here is required, so that later appends
51+
# do not break these dicts
52+
mesh.cell_data['gmsh:physical'] = cell_ids.copy()
53+
mesh.cell_data['gmsh:geometrical'] = cell_ids.copy()
54+
55+
# Build the face elements
56+
logger.info('Converting nodesets to face elements, tags...')
57+
new_tris, tri_nodeset, tri_region = [], [], []
58+
new_quads, quad_nodeset, quad_region = [], [], []
59+
60+
for nodeset_id, nodeset_name in enumerate(mesh.point_sets):
61+
logger.info(' %s' % (nodeset_name))
62+
mesh.field_data[nodeset_name] = [nodeset_id + n_regions + 1, 2]
63+
nodeset = mesh.point_sets[nodeset_name]
64+
65+
# Search by block, then element
66+
for block_id, block in enumerate(mesh.cells):
67+
for element_id, element in enumerate(block[1]):
68+
# Find any matching nodes
69+
matching_nodes = [x for x in element if x in nodeset]
70+
71+
# Add a new face element if there are enough nodes
72+
n_matching = len(matching_nodes)
73+
if (n_matching >= 3):
74+
# Find the region
75+
region_id = -1
76+
for region in region_list:
77+
if (element_id in mesh.cell_sets[region][block_id]):
78+
region_id = mesh.field_data[region][block_id]
79+
80+
# Test to see if the element is a quad or triangle
81+
tag_id = mesh.field_data[nodeset_name][0]
82+
if (n_matching == 3):
83+
new_tris.append(matching_nodes)
84+
tri_nodeset.append(tag_id)
85+
tri_region.append(region_id)
86+
87+
elif (n_matching == 4):
88+
new_quads.append(matching_nodes)
89+
quad_nodeset.append(tag_id)
90+
quad_region.append(region_id)
91+
92+
else:
93+
logger.warning(' Discarding an element with an unexpected number of nodes')
94+
logger.warning(' n_nodes=%i, element=%i, set=%s' % (n_matching, element_id, nodeset_name))
95+
n_warnings += 1
96+
97+
# Add new tris
98+
if new_tris:
99+
logger.info(' Adding %i new triangles...' % (len(new_tris)))
100+
if (-1 in tri_region):
101+
logger.warning('Triangles with empty region information found!')
102+
logger.warning('Note: These will be indicated by a -1 in the output file.')
103+
n_warnings += 1
104+
mesh.cells.append(CellBlock('triangle', np.array(new_tris)))
105+
mesh.cell_data['gmsh:geometrical'].append(np.array(tri_region))
106+
mesh.cell_data['gmsh:physical'].append(np.array(tri_nodeset))
107+
108+
# Add new quads
109+
if new_quads:
110+
logger.info(' Adding %i new quads...' % (len(new_quads)))
111+
if (-1 in quad_region):
112+
logger.warning('Quads with empty region information found!')
113+
logger.warning('Note: These will be indicated by a -1 in the output file.')
114+
n_warnings += 1
115+
mesh.cells.append(CellBlock('quad', np.array(new_quads)))
116+
mesh.cell_data['gmsh:geometrical'].append(np.array(quad_region))
117+
mesh.cell_data['gmsh:physical'].append(np.array(quad_nodeset))
118+
119+
# Write the final mesh
120+
logger.info('Writing gmsh mesh...')
121+
meshio.write(output_mesh, mesh, file_format="gmsh22", binary=False)
122+
logger.info('Done!')
123+
124+
return (n_warnings > 0)
125+
126+
127+
def main():
128+
"""
129+
@brief Entry point for the abaqus convertor console script
130+
@arg input_mesh Input abaqus file name
131+
@arg output_mesh Output gmsh file name
132+
"""
133+
134+
# Parse the user arguments
135+
parser = argparse.ArgumentParser()
136+
parser.add_argument('input', type=str, help='Input abaqus mesh file name')
137+
parser.add_argument('output', type=str, help='Output gmsh mesh file name')
138+
parser.add_argument('-v', '--verbose', help='Increase verbosity level', action="store_true")
139+
args = parser.parse_args()
140+
141+
# Set up a logger
142+
logging.basicConfig(level=logging.WARNING)
143+
logger = logging.getLogger(__name__)
144+
if args.verbose:
145+
logger.setLevel(logging.INFO)
146+
147+
# Call the converter
148+
err = convert_abaqus_to_gmsh(args.input, args.output, logger)
149+
if err:
150+
sys.exit('Warnings detected: check the output file for potential errors!')
151+

geosx_mesh_tools_package/setup.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from distutils.core import setup
2+
3+
setup(name='geosx_mesh_tools',
4+
version='0.1.0',
5+
description='Tools for managing meshes in GEOSX',
6+
author='Chris Sherman',
7+
author_email='[email protected]',
8+
packages=['geosx_mesh_tools'],
9+
entry_points={'console_scripts': ['convert_abaqus = geosx_mesh_tools.abaqus_converter:main']},
10+
install_requires=['meshio'])
11+

0 commit comments

Comments
 (0)