What causes "Type of variable cannot be determined"?

I’m new to Numba and I’m trying to accelerate the speed of the following function:

@njit
def generate_mesh(
    f_min,
    f_max,
    port,
    pml_x,
    vertices,
    stl="model.stl",
    factor=30,
    factor_space=15,
    fraction=500,
    res_fraction=[6,6,6],
    cell_ratio=2,
    n=[3, 3, 3],
):
    #np.set_printoptions(threshold=np.inf)

    remesh = False

    if remesh:
        os.system("gmsh -2 remesh.geo -o tmp.stl -format stl")

    # Generate mesh
    unit = 1000  # 1000 = mm
    c = 299792458
    lambda_min = unit * c / f_max

    max_cell = lambda_min / factor
    max_cell_space = lambda_min / factor_space
    min_cell = lambda_min / fraction

    # Load tetrahedral mesh
    #mesh = trimesh.load("data/tmp/" + stl)
    #print(type(mesh))
    #print(mesh)

    # Fetch node coordinates
    #vertices = trimesh.load("data/tmp/" + stl).vertices

    # Clear duplicate axis entries
    x = np.unique(vertices[:, 0])
    y = np.unique(vertices[:, 1])
    z = np.unique(vertices[:, 2])

    # Refine port
    x = np.append(x, [port[0][0], port[1][0]])
    y = np.append(y, [port[0][1], port[1][1]])
    z = np.append(z, [port[0][2], port[1][2]])

    # Complex models
    nodes = len(vertices)
    #if nodes > 100000:
    #mesh = np.array([x,y,z])

    ### if maximum distance > k * lambda
    ### PORT NEEDS REFINEMENT EITHER WAY
    
    if nodes < 100000:
        # Apply edge refinement
        res = [max_cell/res_fraction[0], max_cell/res_fraction[1], max_cell/res_fraction[2]]

        mesh = np.array([], dtype="object")
        for i, axis in enumerate([x, y, z]):
            fine = np.array([])
            edge_refinements = np.array([-np.inf])
            for line in axis:
                edge_refinement = np.array([])
                for m in range(-n[i], n[i] + 1):
                    edge_refinement = np.concatenate((np.array([line + m * res[i]]), edge_refinement))
                edge_refinement = np.sort(edge_refinement)
                for edge in edge_refinement:
                    if edge > np.max(edge_refinements)+min_cell or edge in axis:
                        fine = np.append(fine, edge)
                        
                    #####edge_refinements = np.append(edge_refinements, edge)
            fine = np.array(np.sort(fine))
            if i == 0:
                fine_0 = fine
            elif i == 1:
                fine_1 = fine
            elif i == 2:
                fine_2 = fine
            #print(mesh)
            #input()
            #print(mesh)


        mesh = np.array([fine_0, fine_1, fine_2], dtype="object")


    ###mesh = [x,y,z]
    # Sort original vertices
    x = np.sort(x)
    y = np.sort(y)
    z = np.sort(z)

    # Add lambda/4 + PML padding cells for bounding box
    f_center = (f_min + f_max)/2
    lambda_center = unit * c / f_center
    padding = lambda_center / 8 + pml_x * max_cell_space

    #mesh[0] = np.insert(mesh[0], 0, x[0] - padding)
    mesh[0] = np.append([x[0] - padding], mesh[0])
    mesh[0] = np.append(mesh[0], x[-1] + padding)
    #mesh[1] = np.insert(mesh[1], 0, y[0] - padding)
    mesh[1] = np.append([y[0] - padding], mesh[1])
    mesh[1] = np.append(mesh[1], y[-1] + padding)
    #mesh[2] = np.insert(mesh[2], 0, z[0] - padding)
    mesh[2] = np.append([z[0] - padding], mesh[2])
    mesh[2] = np.append(mesh[2], z[-1] + padding)

    # Global refinement
    for i in range(len(mesh)):
        ax1 = np.array(mesh[i], dtype=np.float64)
        # Add line to every vertex
        axis = np.unique(np.concatenate((np.unique(vertices[:, i]), ax1)))

        to_delete = np.argwhere(np.ediff1d(axis) <= min_cell) + 1
        q = 1
        axis_tmp = axis
        to_delete_tmp = np.array([])
        while (np.argwhere(np.ediff1d(axis_tmp) <= min_cell) + 1).size > 1:
            to_delete_tmp = np.delete(to_delete, np.arange(0, to_delete.size, q))
            axis_tmp = np.delete(axis, to_delete_tmp)
            q += 1

        if to_delete_tmp.size != 0:
            axis = np.delete(axis, to_delete_tmp)

        # Interior + exterior refinement
        j_tot = (np.argwhere(np.abs(np.ediff1d(axis)) >= max_cell) + 1).size
        for count, j in enumerate(
            (np.argwhere(np.abs(np.ediff1d(axis)) >= max_cell) + 1)
        ):
            if count != 0 and count != j_tot - 1: # Interior
                n = int((np.abs((axis[j - 1] - axis[j]) / max_cell) + 1)[0])
            else: # Exterior
                n = int((np.abs((axis[j - 1] - axis[j]) / max_cell_space) + 1)[0])
            delta = np.abs(axis[j - 1] - axis[j]) / n
            for k in range(n):
                axis = np.append(axis, axis[j - 1] + k * delta)
    
        # Assert no cell exceeds minimum cell size (e.g. 35 um trace thickness)
        #axis = np.delete(axis, np.argwhere(np.ediff1d(axis) <= min_cell) + 1)

        axis = np.unique(axis)
        axis = np.sort(axis)
        
        ###### add 35 micrometer traces
        ######axis = np.unique(np.concatenate((np.unique(vertices[:,i]), axis)))

        mesh[i] = axis


    plot = False
    if plot:
        plt.title("Mesh Sequence")
        plt.plot(mesh[0], ".", label="X-axis")
        plt.plot(mesh[1], ".", label="Y-axis")
        plt.plot(mesh[2], ".", label="Z-axis")
        plt.xlabel("Mesh line index")
        plt.ylabel("Position")
        plt.legend()
        plt.grid()
        plt.show()

    # Delete temporary STL model
    #try:
    #    os.remove("data/tmp/" + stl)
    #except OSError:
    #    pass

    return mesh

However, I get the following error:

Traceback (most recent call last):
  File "solver_api.py", line 1077, in <module>
    mesh = generate_mesh(f_min, f_max, port, pml_x, vertices, stl="model.stl", factor=factor, factor_space=factor_space, fraction=fraction, res_fraction=[6,6,6], cell_ratio=2, n=[3, 3, 3])
  File "/home/abc/.local/lib/python3.8/site-packages/numba/core/dispatcher.py", line 468, in _compile_for_args
    error_rewrite(e, 'typing')
  File "/home/abc/.local/lib/python3.8/site-packages/numba/core/dispatcher.py", line 409, in error_rewrite
    raise e.with_traceback(None)
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Type of variable 'ax1' cannot be determined, operation: call $842load_attr.3($848binary_subscr.6, func=$842load_attr.3, args=[Var($848binary_subscr.6, solver_api.py:249)], kws=[('dtype', Var($852load_attr.8, solver_api.py:249))], vararg=None, target=None), location: solver_api.py (249)

File "solver_api.py", line 249:
def generate_mesh(
    <source elided>
    for i in range(len(mesh)):
        ax1 = np.array(mesh[i], dtype=np.float64)
        ^

How exactly do I resolve this? I couldn’t figure out how to help Numba “determine its variable type”.

hi @0xCoto , what’s would an example of the value of mesh[i]?

@luk-f-a A 1D array, e.g. [1, 2, 5, 19, 23, 31].

So an example of mesh would be:

[
  [1,2,3,4,5,6,7],
  [8,9,10,11,12,13,14,15],
  [16,17,18,19,20,21]
]

mesh will always contain three 1D arrays, but each 1D array may contain an arbitrary number of elements.

thanks, I get it now. I think the (non obvious) problem is that you can’t create an 'object' array inside the njit function. Look at this simple example

@njit
def foo():
    mesh = np.array([], dtype="object")
    return mesh
foo()
Type of variable 'mesh' cannot be determined, operation: call $4load_attr.1($6build_list.2, func=$4load_attr.1, args=[Var($6build_list.2, <ipython-input-14-583ab6c9c755>:3)], kws=[('dtype', Var($const8.3, <ipython-input-14-583ab6c9c755>:3))], vararg=None, target=None), location: <ipython-input-14-583ab6c9c755> (3)

I would suggest you try making mesh just a list, not an array, ie mesh = [fine_0, fine_1, fine_2]. I think this should work, and it won’t change anything important.

Luk

@luk-f-a Doesn’t appear to make much of a difference. I updated the code based on your suggestion to make mesh a list instead of a np array, but the same problem occurs:

@njit
def generate_mesh(
    f_min,
    f_max,
    port,
    pml_x,
    vertices,
    stl="model.stl",
    factor=30,
    factor_space=15,
    fraction=500,
    res_fraction=[6,6,6],
    cell_ratio=2,
    n=[3, 3, 3],
):
    #np.set_printoptions(threshold=np.inf)

    remesh = False

    if remesh:
        os.system("gmsh -2 remesh.geo -o tmp.stl -format stl")

    # Generate mesh
    unit = 1000  # 1000 = mm
    c = 299792458
    lambda_min = unit * c / f_max

    max_cell = lambda_min / factor
    max_cell_space = lambda_min / factor_space
    min_cell = lambda_min / fraction

    # Load tetrahedral mesh
    #mesh = trimesh.load("data/tmp/" + stl)
    #print(type(mesh))
    #print(mesh)

    # Fetch node coordinates
    #vertices = trimesh.load("data/tmp/" + stl).vertices

    # Clear duplicate axis entries
    x = np.unique(vertices[:, 0])
    y = np.unique(vertices[:, 1])
    z = np.unique(vertices[:, 2])

    # Refine port
    x = np.append(x, [port[0][0], port[1][0]])
    y = np.append(y, [port[0][1], port[1][1]])
    z = np.append(z, [port[0][2], port[1][2]])

    # Complex models
    nodes = len(vertices)
    #if nodes > 100000:
    #mesh = np.array([x,y,z])

    ### if maximum distance > k * lambda
    ### PORT NEEDS REFINEMENT EITHER WAY
    
    if nodes < 100000:
        # Apply edge refinement
        res = [max_cell/res_fraction[0], max_cell/res_fraction[1], max_cell/res_fraction[2]]

        #mesh = np.array([], dtype="object")
        for i, axis in enumerate([x, y, z]):
            fine = np.array([])
            edge_refinements = np.array([-np.inf])
            for line in axis:
                edge_refinement = np.array([])
                for m in range(-n[i], n[i] + 1):
                    edge_refinement = np.concatenate((np.array([line + m * res[i]]), edge_refinement))
                edge_refinement = np.sort(edge_refinement)
                for edge in edge_refinement:
                    if edge > np.max(edge_refinements)+min_cell or edge in axis:
                        fine = np.append(fine, edge)
                        
                    #####edge_refinements = np.append(edge_refinements, edge)
            fine = np.array(np.sort(fine))
            if i == 0:
                fine_0 = fine
            elif i == 1:
                fine_1 = fine
            elif i == 2:
                fine_2 = fine
            #print(mesh)
            #input()
            #print(mesh)


        mesh = [fine_0, fine_1, fine_2]


    ###mesh = [x,y,z]
    # Sort original vertices
    x = np.sort(x)
    y = np.sort(y)
    z = np.sort(z)

    # Add lambda/4 + PML padding cells for bounding box
    f_center = (f_min + f_max)/2
    lambda_center = unit * c / f_center
    padding = lambda_center / 8 + pml_x * max_cell_space

    #mesh[0] = np.insert(mesh[0], 0, x[0] - padding)
    mesh[0] = np.append([x[0] - padding], mesh[0])
    mesh[0] = np.append(mesh[0], x[-1] + padding)
    #mesh[1] = np.insert(mesh[1], 0, y[0] - padding)
    mesh[1] = np.append([y[0] - padding], mesh[1])
    mesh[1] = np.append(mesh[1], y[-1] + padding)
    #mesh[2] = np.insert(mesh[2], 0, z[0] - padding)
    mesh[2] = np.append([z[0] - padding], mesh[2])
    mesh[2] = np.append(mesh[2], z[-1] + padding)

    # Global refinement
    for i in range(len(mesh)):
        axis = mesh[i]
        # Add line to every vertex
        axis = np.unique(np.concatenate((np.unique(vertices[:, i]), axis)))

        to_delete = np.argwhere(np.ediff1d(axis) <= min_cell) + 1
        q = 1
        axis_tmp = axis
        to_delete_tmp = np.array([])
        while (np.argwhere(np.ediff1d(axis_tmp) <= min_cell) + 1).size > 1:
            to_delete_tmp = np.delete(to_delete, np.arange(0, to_delete.size, q))
            axis_tmp = np.delete(axis, to_delete_tmp)
            q += 1

        if to_delete_tmp.size != 0:
            axis = np.delete(axis, to_delete_tmp)

        # Interior + exterior refinement
        j_tot = (np.argwhere(np.abs(np.ediff1d(axis)) >= max_cell) + 1).size
        for count, j in enumerate(
            (np.argwhere(np.abs(np.ediff1d(axis)) >= max_cell) + 1)
        ):
            if count != 0 and count != j_tot - 1: # Interior
                n = int((np.abs((axis[j - 1] - axis[j]) / max_cell) + 1)[0])
            else: # Exterior
                n = int((np.abs((axis[j - 1] - axis[j]) / max_cell_space) + 1)[0])
            delta = np.abs(axis[j - 1] - axis[j]) / n
            for k in range(n):
                axis = np.append(axis, axis[j - 1] + k * delta)
    
        # Assert no cell exceeds minimum cell size (e.g. 35 um trace thickness)
        #axis = np.delete(axis, np.argwhere(np.ediff1d(axis) <= min_cell) + 1)

        axis = np.unique(axis)
        axis = np.sort(axis)
        
        ###### add 35 micrometer traces
        ######axis = np.unique(np.concatenate((np.unique(vertices[:,i]), axis)))

        mesh[i] = axis

Output

Traceback (most recent call last):
  File "solver_api.py", line 1077, in <module>
    mesh = generate_mesh(f_min, f_max, port, pml_x, vertices, stl="model.stl", factor=factor, factor_space=factor_space, fraction=fraction, res_fraction=[6,6,6], cell_ratio=2, n=[3, 3, 3])
  File "/home/abc/.local/lib/python3.8/site-packages/numba/core/dispatcher.py", line 468, in _compile_for_args
    error_rewrite(e, 'typing')
  File "/home/abc/.local/lib/python3.8/site-packages/numba/core/dispatcher.py", line 409, in error_rewrite
    raise e.with_traceback(None)
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Type of variable 'axis.1' cannot be determined, operation: getitem(value=mesh, index=i.1, fn=<built-in function getitem>), location: solver_api.py (249)

File "solver_api.py", line 249:
def generate_mesh(
    <source elided>
    for i in range(len(mesh)):
        axis = mesh[i]
        ^

My guess here is that axis.1 hints at something going wrong with SSA. I see you are using axis in several loops. Maybe it makes sense to rename the use of axis in the loop starting for i, axis in enumerate([x, y, z]): – a wild guess but perhaps worth a shot.

@esc Changed the segment of the code from…

    # Global refinement
    for i, axis in enumerate(mesh):
        # Add line to every vertex
        axis = np.unique(np.concatenate((np.unique(vertices[:, i]), axis)))
 
        to_delete = np.argwhere(np.ediff1d(axis) <= min_cell) + 1
        q = 1
        axis_tmp = axis #.copy()
        to_delete_tmp = np.array([])
        while (np.argwhere(np.ediff1d(axis_tmp) <= min_cell) + 1).size > 1:
            to_delete_tmp = np.delete(
                to_delete, np.arange(0, to_delete.size, q))
            axis_tmp = np.delete(axis, to_delete_tmp)
            q += 1
 
        if to_delete_tmp.size != 0:
            axis = np.delete(axis, to_delete_tmp)
 
        # Interior + exterior refinement
        j_tot = (np.argwhere(np.abs(np.ediff1d(axis)) >= max_cell) + 1).size
        for count, j in enumerate(
            (np.argwhere(np.abs(np.ediff1d(axis)) >= max_cell) + 1)
        ):
            if count != 0 and count != j_tot - 1: # Interior
                n = int(np.abs((axis[j - 1] - axis[j]) / max_cell) + 1)
            else: # Exterior
                n = int(np.abs((axis[j - 1] - axis[j]) / max_cell_space) + 1)
            delta = np.abs(axis[j - 1] - axis[j]) / n
            for k in range(n):
                axis = np.append(axis, axis[j - 1] + k * delta)
    
        # Assert no cell exceeds minimum cell size (e.g. 35 um trace thickness)
        axis = np.delete(axis, np.argwhere(np.ediff1d(axis) <= min_cell) + 1)
 
        axis = np.unique(axis)
        axis = np.sort(axis)
        
        ###### add 35 micrometer traces
        ######axis = np.unique(np.concatenate((np.unique(vertices[:,i]), axis)))
 
        mesh[i] = axis #.tolist()

to…

    # Global refinement
    for i, ax1 in enumerate(mesh):
        # Add line to every vertex
        ax = np.unique(np.concatenate((np.unique(vertices[:, i]), ax1)))
 
        to_delete = np.argwhere(np.ediff1d(ax) <= min_cell) + 1
        q = 1
        axis_tmp = ax #.copy()
        to_delete_tmp = np.array([])
        while (np.argwhere(np.ediff1d(axis_tmp) <= min_cell) + 1).size > 1:
            to_delete_tmp = np.delete(
                to_delete, np.arange(0, to_delete.size, q))
            axis_tmp = np.delete(ax, to_delete_tmp)
            q += 1
 
        if to_delete_tmp.size != 0:
            ax = np.delete(ax, to_delete_tmp)
 
        # Interior + exterior refinement
        j_tot = (np.argwhere(np.abs(np.ediff1d(ax)) >= max_cell) + 1).size
        for count, j in enumerate(
            (np.argwhere(np.abs(np.ediff1d(ax)) >= max_cell) + 1)
        ):
            if count != 0 and count != j_tot - 1: # Interior
                n = int(np.abs((ax[j - 1] - ax[j]) / max_cell) + 1)
            else: # Exterior
                n = int(np.abs((ax[j - 1] - ax[j]) / max_cell_space) + 1)
            delta = np.abs(ax[j - 1] - ax[j]) / n
            for k in range(n):
                ax = np.append(ax, ax[j - 1] + k * delta)
    
        # Assert no cell exceeds minimum cell size (e.g. 35 um trace thickness)
        ax = np.delete(ax, np.argwhere(np.ediff1d(ax) <= min_cell) + 1)
 
        ax = np.unique(ax)
        ax = np.sort(ax)
        
        ###### add 35 micrometer traces
        ######axis = np.unique(np.concatenate((np.unique(vertices[:,i]), axis)))
 
        mesh[i] = ax #.tolist()

But the problem remains:

Traceback (most recent call last):
  File "/home/apostolos/Desktop/api/solver_api.py", line 999, in <module>
    mesh = generate_mesh(f_min, f_max, port, pml_x, vertices, stl="model.stl", factor=factor, factor_space=factor_space, fraction=fraction, res_fraction=[6,6,6], cell_ratio=2, n=[3, 3, 3])
  File "/home/apostolos/.local/lib/python3.10/site-packages/numba/core/dispatcher.py", line 468, in _compile_for_args
    error_rewrite(e, 'typing')
  File "/home/apostolos/.local/lib/python3.10/site-packages/numba/core/dispatcher.py", line 409, in error_rewrite
    raise e.with_traceback(None)
numba.core.errors.TypingError: Failed in nopython mode pipeline (step: nopython frontend)
Type of variable 'ax' cannot be determined, operation: call $802load_method.6($832call_method.22, func=$802load_method.6, args=[Var($832call_method.22, solver_api.py:171)], kws=(), vararg=None, varkwarg=None, target=None), location: /home/apostolos/Desktop/api/solver_api.py (171)

File "solver_api.py", line 171:
def generate_mesh(
    <source elided>
        # Add line to every vertex
        ax = np.unique(np.concatenate((np.unique(vertices[:, i]), ax1)))
        ^

Thank you for your response. It does seem like the error is a different one now though?

If possible, can you submit a runnable script. I.e. something that I could experiment with on my machine?

@esc Appreciate your time, this should run (until you uncomment #@njit):

from numba import njit
import numpy as np

#@njit
def generate_mesh(
    f_min,
    f_max,
    port,
    pml_x,
    vertices,
    stl="model.stl",
    factor=30,
    factor_space=15,
    fraction=500,
    res_fraction=[6,6,6],
    cell_ratio=2,
    n=[3, 3, 3],
):
    #np.set_printoptions(threshold=np.inf)

    # Generate mesh
    unit = 1000  # 1000 = mm
    c = 299792458
    lambda_min = unit * c / f_max

    max_cell = lambda_min / factor
    max_cell_space = lambda_min / factor_space
    min_cell = lambda_min / fraction

    # Load tetrahedral mesh
    #mesh = trimesh.load("data/tmp/" + stl)
    #print(type(mesh))
    #print(mesh)

    # Fetch node coordinates
    #vertices = trimesh.load("data/tmp/" + stl).vertices

    # Clear duplicate axis entries
    x = np.unique(vertices[:, 0])
    y = np.unique(vertices[:, 1])
    z = np.unique(vertices[:, 2])

    # Refine port
    x = np.append(x, [port[0][0], port[1][0]])
    y = np.append(y, [port[0][1], port[1][1]])
    z = np.append(z, [port[0][2], port[1][2]])

    # Complex models
    nodes = len(vertices)
    #if nodes > 100000:
    #mesh = np.array([x,y,z])

    ### if maximum distance > k * lambda
    ### PORT NEEDS REFINEMENT EITHER WAY
    
    if nodes < 100000:
        # Apply edge refinement
        res = [max_cell/res_fraction[0], max_cell/res_fraction[1], max_cell/res_fraction[2]]

        #mesh = np.array([], dtype="object")
        for i, axis in enumerate([x, y, z]):
            fine = np.array([])
            edge_refinements = np.array([-np.inf])
            for line in axis:
                edge_refinement = np.array([])
                for m in range(-n[i], n[i] + 1):
                    edge_refinement = np.concatenate((np.array([line + m * res[i]]), edge_refinement))
                edge_refinement = np.sort(edge_refinement)
                for edge in edge_refinement:
                    if edge > np.max(edge_refinements)+min_cell or edge in axis:
                        fine = np.append(fine, edge)
                        
                    #####edge_refinements = np.append(edge_refinements, edge)
            fine = np.array(np.sort(fine))
            if i == 0:
                fine_0 = fine
            elif i == 1:
                fine_1 = fine
            elif i == 2:
                fine_2 = fine


        mesh = [fine_0, fine_1, fine_2]

    # Sort original vertices
    x = np.sort(x)
    y = np.sort(y)
    z = np.sort(z)

    # Add lambda/4 + PML padding cells for bounding box
    f_center = (f_min + f_max)/2
    lambda_center = unit * c / f_center
    padding = lambda_center / 8 + pml_x * max_cell_space

    mesh[0] = np.append([x[0] - padding], mesh[0])
    mesh[0] = np.append(mesh[0], x[-1] + padding)
    mesh[1] = np.append([y[0] - padding], mesh[1])
    mesh[1] = np.append(mesh[1], y[-1] + padding)
    mesh[2] = np.append([z[0] - padding], mesh[2])
    mesh[2] = np.append(mesh[2], z[-1] + padding)

    # Global refinement
    for i, axis in enumerate(mesh):
        # Add line to every vertex
        axis = np.unique(np.concatenate((np.unique(vertices[:, i]), axis)))
 
        to_delete = np.argwhere(np.ediff1d(axis) <= min_cell) + 1
        q = 1
        axis_tmp = axis #.copy()
        to_delete_tmp = np.array([])
        while (np.argwhere(np.ediff1d(axis_tmp) <= min_cell) + 1).size > 1:
            to_delete_tmp = np.delete(
                to_delete, np.arange(0, to_delete.size, q))
            axis_tmp = np.delete(axis, to_delete_tmp)
            q += 1
 
        if to_delete_tmp.size != 0:
            axis = np.delete(axis, to_delete_tmp)
 
        # Interior + exterior refinement
        j_tot = (np.argwhere(np.abs(np.ediff1d(axis)) >= max_cell) + 1).size
        for count, j in enumerate(
            (np.argwhere(np.abs(np.ediff1d(axis)) >= max_cell) + 1)
        ):
            if count != 0 and count != j_tot - 1: # Interior
                n = int(np.abs((axis[j - 1] - axis[j]) / max_cell) + 1)
            else: # Exterior
                n = int(np.abs((axis[j - 1] - axis[j]) / max_cell_space) + 1)
            delta = np.abs(axis[j - 1] - axis[j]) / n
            for k in range(n):
                axis = np.append(axis, axis[j - 1] + k * delta)
    
        # Assert no cell exceeds minimum cell size (e.g. 35 um trace thickness)
        axis = np.delete(axis, np.argwhere(np.ediff1d(axis) <= min_cell) + 1)
 
        axis = np.unique(axis)
        axis = np.sort(axis)
        
        ###### add 35 micrometer traces
        axis = np.unique(np.concatenate((np.unique(vertices[:,i]), axis)))

        mesh[i] = np.unique(np.round(axis, 6)) #.tolist()

    return mesh


# === Inputs and function call ===

f_min = 1000000000
f_max = 3000000000
port = [[0, 1.6, 35], [0, 0, 35]]
pml_x = 8
vertices = np.array(
      [[ 35.        ,   0.        ,  35.        ],
       [-35.        ,   1.60000002,  35.        ],
       [-35.        ,   0.        ,  35.        ],
       [ 35.        ,   1.60000002,  35.        ],
       [-35.        ,   1.60000002, -35.        ],
       [ 35.        ,   0.        , -35.        ],
       [-35.        ,   0.        , -35.        ],
       [ 35.        ,   1.60000002, -35.        ],
       [-35.        ,  -0.035     ,  35.        ],
       [ 35.        ,  -0.035     ,  35.        ],
       [-35.        ,  -0.035     , -35.        ],
       [ 35.        ,  -0.035     , -35.        ],
       [ 24.69000053,   1.63499999,  20.65999985],
       [-24.69000053,   1.63499999,  20.65999985],
       [-24.69000053,   1.60000002,  20.65999985],
       [ 24.69000053,   1.60000002,  20.65999985],
       [-24.69000053,   1.63499999, -20.65999985],
       [ 24.69000053,   1.63499999, -20.65999985],
       [-24.69000053,   1.60000002, -20.65999985],
       [ 24.69000053,   1.60000002, -20.65999985],
       [  2.4749999 ,   1.63499999,  35.        ],
       [ -2.4749999 ,   1.63499999,  35.        ],
       [ -2.4749999 ,   1.60000002,  35.        ],
       [  2.4749999 ,   1.60000002,  35.        ],
       [ -2.4749999 ,   1.63499999,  20.64999962],
       [  2.4749999 ,   1.63499999,  20.64999962],
       [ -2.4749999 ,   1.60000002,  20.64999962],
       [  2.4749999 ,   1.60000002,  20.64999962]]
       )
factor = 60.0
factor_space = 30.0
fraction = 800.0

mesh = generate_mesh(f_min, f_max, port, pml_x, vertices, stl="none", factor=factor, factor_space=factor_space, fraction=fraction, res_fraction=[6,6,6], cell_ratio=2, n=[3, 3, 3])

# Print returned array
print(mesh)

# Print array dimensions (should return be 111x43x94=448662)
print(str(len(mesh[0])) + "x" + str(len(mesh[1])) + "x" + str(len(mesh[2])) + "=" + str(len(mesh[0]) * len(mesh[1]) * len(mesh[2])))

I gave this another shot today, but I didn’t get anywhere, unfortunately. My hunch is now however, that somehow Numba becomes confused about the type of mesh and so it is unable to iterate over it. My recommendation would be to break the code into smaller functions so that it is easier to debug. I think there may be a Numba bug in there somewhere. The other alternative, would be to remove code from the function iteratively until only code that triggers the error remains, that would also make it easier to debug.

1 Like

I went through a lot of testing by cutting the code down, but I still couldn’t get something meaningful running, and couldn’t figure out how to make array operations work properly. :frowning:

Unfortunately, I’ve come to believe Numba acceleration may not be worth it for my particular case (possibly because I’m not too familiar with Numba). My execution time isn’t terrible with regular Python, but I also tried Cython, although the runtime was basically identical to regular Python.

I appreciate the effort though - if you happen to get anywhere further with debugging yourself, I’d be curious to know how you got the whole function working. :slight_smile:

OK, thank you for following up! Glad you managed to find a “resolution”.