Auto name the Part name from .inp file by gmsh

Hello,

I have the assembly with lots of part (more than 100). So I used gmsh to mesh it first, and got lots of .inp files.
When I import .inp files, the part name in PrePoMax only name Solid_part-~.

My .inp file like follows
my_part.inp

*Part, name=my_part
*NODE
...node...
...node...
******* E L E M E N T S *************
*ELEMENT, type=C3D10, ELSET=my_part_element
...element...
...element...

I can only get Element set with the name which I set “my_part_element”. But when I remove the Element set, it is very difficult to find related Part with Element set.

Is there any way to name the Part name automatically?

At the moment this is not possible. Can you share one of the .inp files?

Hi Matej :

Here you are.
frame_fixed_gmsh.inp
The link is valid until 2022/10/31.

My solution is using “Convert to Part” to convert Element sets to Parts. And then, delete each “Solid_part-”.
image

My code of Gmsh as follows:

def gmsh_step_to_stl(file_address, size=3):
    try:
        file_name = file_address.split('\\')[-1]
        size = 0.5 if size < 0.5 else size

        gmsh.initialize()
        gmsh.open(file_address)

        # ent = gmsh.model.getEntities()
        # for e in ent:
        #     n = gmsh.model.getEntityName(e[0], e[1])

        #     if n and e[0]==3:
        #         part_name = n.split('/')[-1]
        #         print(part_name,e)

        gmsh.option.setNumber("Mesh.MeshSizeExtendFromBoundary", 0)
        gmsh.option.setNumber('Mesh.MeshSizeFromCurvature', 8)
        gmsh.option.setNumber('Mesh.MeshSizeMax', size)
        if size/5<0.3:
            gmsh.option.setNumber("Mesh.MeshSizeMin", 0.3)
        else:
            gmsh.option.setNumber("Mesh.MeshSizeMin", size/5)

        try:
            # if second_order_bool:
            #     gmsh.model.mesh.generate(3)
            #     gmsh.model.mesh.setOrder(2)
            # else:
            #     gmsh.model.mesh.generate(3)
            gmsh.model.mesh.generate(2)
        except:
            print(f'WARNING : {file_name} need OCC heal.')
            gmsh.finalize()
            gmsh.initialize()
            gmsh.open(file_address)
            gmsh.model.occ.healShapes()
            gmsh.model.occ.synchronize()
            gmsh.option.setNumber("Mesh.MeshSizeExtendFromBoundary", 0)
            gmsh.option.setNumber('Mesh.MeshSizeFromCurvature', 8)
            gmsh.option.setNumber('Mesh.MeshSizeMax', size)
            if size/5<0.3:
                gmsh.option.setNumber("Mesh.MeshSizeMin", 0.3)
            else:
                gmsh.option.setNumber("Mesh.MeshSizeMin", size/5)
            # if second_order_bool:
            #     gmsh.model.mesh.generate(3)
            #     gmsh.model.mesh.setOrder(2)
            # else:
            #     gmsh.model.mesh.generate(3)
            gmsh.model.mesh.generate(2)
            file_address = file_address.replace(".stp","_OCCHealShape.stp").replace(".step","_OCCHealShape.step")

        file_address = file_address.replace(".stp",".stl").replace(".step",".stl")
        gmsh.write(file_address)

        print(f'{file_name} : Gmsh convert STEP to STL FINISHED.')
        print(f'## Gmsh STEP to STL saved : "{file_address}"')
        gmsh.finalize()
        return file_address
    except:
        [print("\t<<<"+line+">>>") for line in traceback.format_exc().split("\n")]

        print(f'ERROR : gmsh_step_to_stl in {file_address}')
        gmsh.finalize()
        return file_address
def gmsh_stl_to_inp(file_address, size = 3,
                    second_order_bool = True,
                    with_surface_bool = True,
                    remove_degenerate_element_bool = True):
    
    def tetrahedron_volume(tetrahedron_index):
        node_indexs = gmsh.model.mesh.getElement(tetrahedron_index)[1]
        node0 = gmsh.model.mesh.getNode(node_indexs[0])[0]
        u = gmsh.model.mesh.getNode(node_indexs[1])[0] - node0
        v = gmsh.model.mesh.getNode(node_indexs[2])[0] - node0
        w = gmsh.model.mesh.getNode(node_indexs[3])[0] - node0
        d = u[0]*(v[1]*w[2]-v[2]*w[1])+\
            u[1]*(v[2]*w[0]-v[0]*w[2])+\
            u[2]*(v[0]*w[1]-v[1]*w[0])
        return 1.0/(1.0*2.0*3.0) * abs(d)
    
    try:
        gmsh.initialize()

        file_name = file_address.split('\\')[-1]
        print(f'{file_name} : Gmsh convert stl to inp ...')

        # Clear all models and merge an STL mesh that we would like to remesh (from
        # the parent directory):
        gmsh.clear()
        gmsh.merge(file_address)

        # Create a volume from all the surfaces
        s = gmsh.model.getEntities(2)
        l = gmsh.model.geo.addSurfaceLoop([e[1] for e in s])
        gmsh.model.geo.addVolume([l])

        gmsh.model.geo.synchronize()

        # We specify element sizes imposed by a size field, just because we can :-)
        f = gmsh.model.mesh.field.add("MathEval")
        gmsh.model.mesh.field.setString(f, "F", str(int(size)))
        gmsh.model.mesh.field.setAsBackgroundMesh(f)

        if second_order_bool:
            gmsh.model.mesh.generate(3)
            gmsh.model.mesh.setOrder(2)
        else:
            gmsh.model.mesh.generate(3)

        if not with_surface_bool:
            surface_elements_index = []
            for i in [2,3]+[9,10]+[16]+[20,21,22,23,24,25]:
                surface_elements_index += gmsh.model.mesh.getElementsByType(i)[0].tolist()
            gmsh.model.mesh.setVisibility(surface_elements_index, 0)
            gmsh.plugin.setNumber('Invisible', 'DeleteElements', 1)
            gmsh.plugin.run('Invisible')

        if remove_degenerate_element_bool:
            tetrahedron_indexs = gmsh.model.mesh.getElementsByType(11)[0]
            degenerate_element_indexs = []
            for index in tetrahedron_indexs:
                volume = tetrahedron_volume(index)
                if volume<1e-05:
                    degenerate_element_indexs.append(index)
                    print(f'{file_name.replace(".stl","")} tetrahedron element {index} is degenerated, vol= {volume}')
            gmsh.model.mesh.setVisibility(degenerate_element_indexs, 0)
            gmsh.plugin.setNumber('Invisible', 'DeleteElements', 1)
            gmsh.plugin.run('Invisible')
            print(f'Remove {len(degenerate_element_indexs)} degenerated tetrahedrons')

        #gmsh.option.setNumber('Mesh.SaveGroupsOfNodes', 1)
        file_address = file_address.replace("_blender","_gmsh").replace(".stl",".inp")
        gmsh.write(file_address)
        gmsh.finalize()
        
        print(f'{file_name} : Gmsh convert stl to inp FINISHED.')

        f = open(file_address, 'r+',encoding="utf-8")
        f.write( f'*Part, name={file_name.replace("_blender","_gmsh").replace(".stl","")}\n**')
        f.close()
        
        print(f'## Gmsh stl to inp saved : "{file_address}"')
        
        return file_address
    except:
        [print("\t<<<"+line+">>>") for line in traceback.format_exc().split("\n")]
        
        ## open Gmsh
        #gmsh.fltk.run()
        # file_address = file_address.replace("_blender","_error_gmsh").replace(".stl",".inp")
        # gmsh.write(file_address)

        print(f'ERROR : gmsh_stl_to_inp in {file_address}')
        
        gmsh.finalize()
        return file_address

I have changed the .inp reader to account for the *Part keyword, even though Gmesh does not use it correctly. Each *Part keyword should namely end with the *End part keyword.

The problem with the current implementation is that it will work only for a single part saved in a single .inp file. Supporting the whole Abaqus *Assembly keyword is too much work for now.

Why do you mesh the geometry in Gmesh if you are using only tetrahedrons?

Hi Matej,
Thanks for your reply.

Why do you mesh the geometry in Gmesh if you are using only tetrahedrons?

I guess you mean that why don’t I mesh tetrahedrons directly but mesh 2D surface in stl first and then convert it to tetrahedrons.
The reason is that the stp file with defect sometime cannot mesh tetrahedrons directly, even used occ.healShapes ( occ is OpenCascade. It packaged by Gmsh.), so I will get 2D surface mesh in stl and fix it by Blender script automatically.

In addition, I choose Gmsh is just because it is fast, and the mesh kernel in PrePoMax is a little bit slow.