A malloc() mismatch error when importing a GMSH mesh

Hello,

I have run into a problem when trying to import a mesh with the function dolfinx.io.gmshio.model_to_mesh. I obtain the following error:

malloc(): mismatching next->prev_size (unsorted)

I was using a similar mesh up to now without any problems. I also output the mesh to a file and check it with the GMSH GUI, and it seems okay.

I would appreciate any help or suggestion what could have gone wrong.

The full error message is:

malloc(): mismatching next->prev_size (unsorted)
[DESKTOP-UNNANJK:02638] *** Process received signal ***
[DESKTOP-UNNANJK:02638] Signal: Aborted (6)
[DESKTOP-UNNANJK:02638] Signal code:  (-6)
[DESKTOP-UNNANJK:02638] [ 0] /lib/x86_64-linux-gnu/libc.so.6(+0x42520)[0x7f4ded922520]
[DESKTOP-UNNANJK:02638] [ 1] /lib/x86_64-linux-gnu/libc.so.6(pthread_kill+0x12c)[0x7f4ded976a7c]
[DESKTOP-UNNANJK:02638] [ 2] /lib/x86_64-linux-gnu/libc.so.6(raise+0x16)[0x7f4ded922476]
[DESKTOP-UNNANJK:02638] [ 3] /lib/x86_64-linux-gnu/libc.so.6(abort+0xd3)[0x7f4ded9087f3]
[DESKTOP-UNNANJK:02638] [ 4] /lib/x86_64-linux-gnu/libc.so.6(+0x896f6)[0x7f4ded9696f6]
[DESKTOP-UNNANJK:02638] [ 5] /lib/x86_64-linux-gnu/libc.so.6(+0xa0d7c)[0x7f4ded980d7c]
[DESKTOP-UNNANJK:02638] [ 6] /lib/x86_64-linux-gnu/libc.so.6(+0xa43fc)[0x7f4ded9843fc]
[DESKTOP-UNNANJK:02638] [ 7] /lib/x86_64-linux-gnu/libc.so.6(malloc+0x99)[0x7f4ded9851b9]
[DESKTOP-UNNANJK:02638] [ 8] /home/przemo/mambaforge/lib/../lib/libstdc++.so.6(_Znwm+0x1c)[0x7f4de76aab48]
[DESKTOP-UNNANJK:02638] [ 9] /home/przemo/mambaforge/lib/python3.10/site-packages/dolfinx/../../../libdolfinx.so.0.6(+0x1413b7)[0x7f4daef553b7]
[DESKTOP-UNNANJK:02638] [10] /home/przemo/mambaforge/lib/python3.10/site-packages/dolfinx/../../../libdolfinx.so.0.6(_ZN7dolfinx4mesh11create_meshEP19ompi_communicator_tRKNS_5graph13AdjacencyListIlEERKNS_3fem17CoordinateElementESt4spanIKdLm18446744073709551615EESt5arrayImLm2EERKSt8functionIFNS4_IiEES2_iiS7_EE+0x3a9)[0x7f4daef55a09]
[DESKTOP-UNNANJK:02638] [11] /home/przemo/mambaforge/lib/python3.10/site-packages/dolfinx/cpp.cpython-310-x86_64-linux-gnu.so(+0x1d4f1d)[0x7f4daf1d7f1d]
[DESKTOP-UNNANJK:02638] [12] /home/przemo/mambaforge/lib/python3.10/site-packages/dolfinx/cpp.cpython-310-x86_64-linux-gnu.so(+0x77ce0)[0x7f4daf07ace0]
[DESKTOP-UNNANJK:02638] [13] /home/przemo/mambaforge/bin/python(+0x1406b7)[0x7f4deddc56b7]
[DESKTOP-UNNANJK:02638] [14] /home/przemo/mambaforge/bin/python(_PyObject_MakeTpCall+0x26b)[0x7f4deddbecdb]
[DESKTOP-UNNANJK:02638] [15] /home/przemo/mambaforge/bin/python(_PyEval_EvalFrameDefault+0x559e)[0x7f4deddbaace]
[DESKTOP-UNNANJK:02638] [16] /home/przemo/mambaforge/bin/python(_PyFunction_Vectorcall+0x6f)[0x7f4deddc5b1f]
[DESKTOP-UNNANJK:02638] [17] /home/przemo/mambaforge/bin/python(_PyEval_EvalFrameDefault+0x332)[0x7f4deddb5862]
[DESKTOP-UNNANJK:02638] [18] /home/przemo/mambaforge/bin/python(_PyFunction_Vectorcall+0x6f)[0x7f4deddc5b1f]
[DESKTOP-UNNANJK:02638] [19] /home/przemo/mambaforge/bin/python(_PyEval_EvalFrameDefault+0x13d0)[0x7f4deddb6900]
[DESKTOP-UNNANJK:02638] [20] /home/przemo/mambaforge/bin/python(+0x1db6a2)[0x7f4dede606a2]
[DESKTOP-UNNANJK:02638] [21] /home/przemo/mambaforge/bin/python(PyEval_EvalCode+0x87)[0x7f4dede605e7]
[DESKTOP-UNNANJK:02638] [22] /home/przemo/mambaforge/bin/python(+0x20e3fc)[0x7f4dede933fc]
[DESKTOP-UNNANJK:02638] [23] /home/przemo/mambaforge/bin/python(+0x2092d4)[0x7f4dede8e2d4]
[DESKTOP-UNNANJK:02638] [24] /home/przemo/mambaforge/bin/python(+0x9758d)[0x7f4dedd1c58d]
[DESKTOP-UNNANJK:02638] [25] /home/przemo/mambaforge/bin/python(_PyRun_SimpleFileObject+0x1b5)[0x7f4dede884f5]
[DESKTOP-UNNANJK:02638] [26] /home/przemo/mambaforge/bin/python(_PyRun_AnyFileObject+0x43)[0x7f4dede880a3]
[DESKTOP-UNNANJK:02638] [27] /home/przemo/mambaforge/bin/python(Py_RunMain+0x399)[0x7f4dede85279]
[DESKTOP-UNNANJK:02638] [28] /home/przemo/mambaforge/bin/python(Py_BytesMain+0x39)[0x7f4dede52dc9]
[DESKTOP-UNNANJK:02638] [29] /lib/x86_64-linux-gnu/libc.so.6(+0x29d90)[0x7f4ded909d90]
[DESKTOP-UNNANJK:02638] *** End of error message ***
Aborted (core dumped)

The code that I have up to the point:

def _shift_points_2d(p, dx=0, dy=0): return [(x[0]+dx, x[1]+dy) for x in p]
def _shift_points_3d(p, dx=0, dy=0, dz=0): return [(x[0]+dx, x[1]+dy, x[2]+dz) for x in p]
def _mirror_along_x(p, x0=0): return [ (x[0], -x[1]) for x in p]
def _mirror_along_y(p, y0=0): return [ (-x[0], x[1]) for x in p]

def set_remove_list(s, c): 
    t = s.copy()
    t.difference_update(c)
    return t

def tags_filter_2d(t):
    tags = []
    for tag in t:
        if tag[0]==2:
            tags.append(tag[1])
    return tags

def tags_filter_3d(t):
    tags = []
    for tag in t:
        if tag[0]==3:
            tags.append(tag[1])
    return tags

def extrude_from_points_list(_gmsh, p, dz, z0=0):
    # a list of tags of all the points that will be created
    p_tags = [gmsh.model.occ.addPoint(x[0], x[1], z0 ) for x in p]
    # a list of tags of all the lines connecting the points
    lines = [gmsh.model.occ.addLine(p_tags[i], p_tags[i+1]) for i in range(len(p_tags)-1)]
    lines.append(gmsh.model.occ.addLine(p_tags[-1], p_tags[0]))
    # now it is a loop
    loop = gmsh.model.occ.addCurveLoop(lines)
    # create a surface out of the wires loop
    face = gmsh.model.occ.addPlaneSurface([loop])
    # extrude the surface so a volume is obtained
    objs = gmsh.model.occ.extrude([(2,face)], 0,0, dz)

    volumes = tags_filter_3d(objs)
    walls = tags_filter_2d(objs)
    
    return volumes, walls


mesh_filename = '02_mesh.msh'
resolution = 1 # Normal resolution
resolution_hq = 0.1 # High Quality resolution

# Pick some tags for the elements
SUBS_VOLUME_TAG = 1
AIR_VOLUME_TAG = 2

METAL_WALLS_TAG = 1
MICROSTRIP1_WALLS_TAG = 2
MICROSTRIP2_WALLS_TAG = 3
SUBS_AIR_WALLS_TAG = 4
PBC_WALLS_TAG = 5

# The microstrip thickness and coordinates of the points (x, y)
L = 2
metal_th = 0.025
metal_gap = 0.5
tw1 = 0.4
tw2 = 0.4
th1 = 0.9
th2 = 0.9
line1_w = 0.7
line2_w = 0.7

assert(th1+th2<L)
assert( max([tw1, tw2])<metal_gap)

metal1_points = [(0, -line1_w), (L, -line1_w), (L, 0.0), ((L+th1)/2, 0.0), ((L+th1)/2, 0.0+tw1), ((L-th1)/2, 0.0+tw1), ((L-th1)/2, 0.0), (0, 0.0)]
metal2_points = [(0, -0.0-tw2), (th2/2, -0.0-tw2), (th2/2, -0.0), (L-th2/2, -0.0), (L-th2/2, -0.0-tw2), (L, -0.0-tw2), (L, line2_w), (0.0, line2_w)]
metal1_points = _shift_points_2d(metal1_points, dy=-metal_gap/2)
metal2_points = _shift_points_2d(metal2_points, dy=metal_gap/2)

# The substrate width, length and thickness
subs_w, subs_h, subs_th = L, 10, 0.254
# The substrate dielectic constant
subs_er = 2.33
# The air box above width, length and height
air_w, air_h, air_th = subs_w, subs_h, 5

import gmsh
gmsh.initialize()
gmsh.option.setNumber("General.Terminal", 0) # disable console output

#%% The first part - prepare the model
# Create a new (and only model)
gmsh.model.add("dut")

# Preapre the substrate and the air volumes
substrate = gmsh.model.occ.addBox(0, -subs_h/2, -subs_th, subs_w, subs_h, subs_th)
air = gmsh.model.occ.addBox(0, -air_h/2, 0, air_w, air_h, air_th)

# Create the metal volume

metal1_volumes, metal1_walls = extrude_from_points_list(gmsh, metal1_points, dz=metal_th)
metal2_volumes, metal2_walls = extrude_from_points_list(gmsh, metal2_points, dz=metal_th)

# Remove the metal volume from the air volume
# We want to first remove the metal form the air, and then from the substrate, so in the first occ.cut there is removeTool=False
# Unfortunately it seems that in the current version cut_map can't help us yet
cut_result, cut_map = gmsh.model.occ.cut([(3, air)], [(3, metal1_volumes[0]), (3, metal2_volumes[0])], removeTool=False)
air = cut_result[0][1]

cut_result, cut_map  = gmsh.model.occ.cut([(3, substrate)], [(3, metal1_volumes[0]), (3, metal2_volumes[0])])
substrate = cut_result[0][1]

# The most important thing, do the boolean fragment - then the mesh is conformal
gmsh.model.occ.fragment([(3, air), (3, substrate)], [ ])

#%% The second part - assign tags
gmsh.model.occ.synchronize()

# there are no 4d objects available
_, substrate_adj_surfaces = gmsh.model.getAdjacencies(3, substrate)
_, air_adj_surfaces = gmsh.model.getAdjacencies(3, air)

# let's change the lists to sets, surface tags are unique afterall
substrate_adj_surfaces = set(substrate_adj_surfaces)
air_adj_surfaces = set(air_adj_surfaces)

common_surfaces = substrate_adj_surfaces & air_adj_surfaces
substrate_unique_surfaces = set_remove_list(substrate_adj_surfaces, common_surfaces)
air_unique_surfaces = set_remove_list(air_adj_surfaces, common_surfaces)
all_surfaces = substrate_adj_surfaces | air_adj_surfaces

# Periodic Boundary Condition walls
pbc_walls = []
# Metal Box walls
metal_walls = []
# Microstrip walls
microstrip1_walls = []
microstrip2_walls = []
# The air-substrate interface
subs_air_interface = list(common_surfaces.copy())


for tag in all_surfaces:

    comx, comy, comz = gmsh.model.occ.getCenterOfMass(2, tag)
    xmin, ymin, zmin, xmax, ymax, zmax = gmsh.model.occ.getBoundingBox(2, tag) # return xmin ymin zmin xmax ymax zmax

    if tag in air_unique_surfaces and (zmax>2*metal_th) and (xmax-xmin>L/2):
        metal_walls.append(tag)
    elif tag in air_unique_surfaces and (zmax>2*metal_th) and (xmax-xmin<L/2):
        pbc_walls.append(tag)
    elif tag in substrate_unique_surfaces and (zmin<-subs_th/2) and (xmax-xmin>L/2):
        metal_walls.append(tag)
    elif tag in substrate_unique_surfaces and (zmin<-subs_th/2) and (xmax-xmin<L/2):
        pbc_walls.append(tag)
    elif tag in substrate_unique_surfaces and not tag in common_surfaces and comy<0:
        microstrip1_walls.append(tag)
    elif tag in substrate_unique_surfaces and not tag in common_surfaces and comy>0:
        microstrip2_walls.append(tag)

# The remaining tags belong to microstrip1 and microstrip2, let's try to get them in another way
def _find_adj_walls(mtl_tag, cond=True):
    _, mtl_adj_points = gmsh.model.getAdjacencies(2, mtl_tag)

    mtl_walls = set([])
    for p in mtl_adj_points:
        p_adj_surfaces, _= gmsh.model.getAdjacencies(1, p)

        for s in p_adj_surfaces:
            comx, comy, comz = gmsh.model.occ.getCenterOfMass(2, s)

            if (cond and comz>metal_th/4 and comz<3/4*metal_th) or not cond:
                mtl_walls.add(s)
    return mtl_walls

def _find_shared_walls(mtl_tags):

    shared_walls = None
    for tag in mtl_tags:
        walls = _find_adj_walls(tag, cond=False)
        
        if shared_walls is None:
            shared_walls = set(walls)
        else:
            shared_walls = shared_walls & walls
    return shared_walls

# The strategy is: we easily managed to identified the microstrip 1 and 2 on the interface between the substrate and air, because
# it is just one surface each with distinct COM
# The rest we identify by finding the walls adjecent to this distinct surfaces that have z-comp. of the COM in the microstrip
# The final "roof" surface is found as the shared wall among the ones from the previous step
mtl1_adj_walls = _find_adj_walls(microstrip1_walls[0])
mtl2_adj_walls = _find_adj_walls(microstrip2_walls[0])

mtl1_shared_walls = _find_shared_walls(mtl1_adj_walls)
mtl2_shared_walls = _find_shared_walls(mtl2_adj_walls)
mtl1_adj_walls.update(mtl1_shared_walls)
mtl2_adj_walls.update(mtl2_shared_walls)

microstrip1_walls.extend(mtl1_adj_walls)
microstrip2_walls.extend(mtl2_adj_walls)


gmsh.model.addPhysicalGroup(2, pbc_walls, PBC_WALLS_TAG)
gmsh.model.setPhysicalName(2, PBC_WALLS_TAG, "Periodic BC")
gmsh.model.addPhysicalGroup(2, metal_walls, METAL_WALLS_TAG)
gmsh.model.setPhysicalName(2, METAL_WALLS_TAG, "PEC Box")
gmsh.model.addPhysicalGroup(2, microstrip1_walls, MICROSTRIP1_WALLS_TAG)
gmsh.model.setPhysicalName(2, MICROSTRIP1_WALLS_TAG, "PEC Microstrip 1")
gmsh.model.addPhysicalGroup(2, microstrip2_walls, MICROSTRIP2_WALLS_TAG)
gmsh.model.setPhysicalName(2, MICROSTRIP2_WALLS_TAG, "PEC Microstrip 2")
gmsh.model.addPhysicalGroup(2, subs_air_interface, SUBS_AIR_WALLS_TAG)
gmsh.model.setPhysicalName(2, SUBS_AIR_WALLS_TAG, "Substrate-Air Interface")

#%% Now let's set the meshing

# First we define from which object the distance matters (from the microstrip)
distance = gmsh.model.mesh.field.add("Distance")
microstrip_walls = (microstrip1_walls.copy())
microstrip_walls.extend(microstrip2_walls) # a list of all microstrip wall surfaces
gmsh.model.mesh.field.setNumbers(distance, "FacesList", microstrip_walls)

# So the finest mesh will be up to half of metal_w and then gradually change
# to the regular mesh at the distance of 2x metal_w
threshold = gmsh.model.mesh.field.add("Threshold")
gmsh.model.mesh.field.setNumber(threshold, "IField", distance)
gmsh.model.mesh.field.setNumber(threshold, "LcMin", resolution_hq)
gmsh.model.mesh.field.setNumber(threshold, "LcMax", resolution)
gmsh.model.mesh.field.setNumber(threshold, "DistMin", resolution_hq*3)
gmsh.model.mesh.field.setNumber(threshold, "DistMax", resolution_hq*10)

# Set the mesh
gmsh.model.mesh.field.setAsBackgroundMesh(threshold)

#%% Generate the mesh and  save it
gmsh.model.occ.synchronize()
gmsh.model.mesh.generate(3)
gmsh.write(mesh_filename)

#%% Load the mesh to DOLFINx
from dolfinx.io.gmshio import model_to_mesh
from mpi4py import MPI
import numpy as np
model_rank = 0
mesh, cell_tags, facet_tags = model_to_mesh(gmsh.model, MPI.COMM_WORLD, model_rank, gdim=3)

I would not synchronize after adding the physical tags (Im not at a computer, so i cannot test it).

Looking at your mesh generation script, you have not added any physical groups for the volume of your mesh. You have to do this to be able to read it from gmsh. You can see this by opening your mesh file, Tools->Visibility and look at physical groups. There are only surfaces there.

Ah well, yes, that is correct. I didn’t add any volume tags. :melting_face:
Thank you for your help.