def convolve_sep3(data, hx, hy, hz, res_g=None, sub_blocks=(1, 1, 1), tmp_g = None):
    """convolves 3d data with kernel h = outer(hx,hy, hz)
    boundary conditions are clamping to edge.

    data, hx, hy.... are either np array or a gpu buffer (OCLArray)

    """

    if isinstance(data, np.ndarray):
        data = np.ascontiguousarray(data)
        if sub_blocks == (1, 1, 1) or sub_blocks is None:
            return _convolve_sep3_numpy(data, hx, hy, hz)
        else:
            # cut the image into tile and operate on every of them
            N_sub = [int(np.ceil(1. * n / s)) for n, s in zip(data.shape, sub_blocks)]
            Npads = [int(len(_h) / 2) for _h in [hz, hy, hx]]
            res = np.empty(data.shape, np.float32)
            for i, (data_tile, data_s_src, data_s_dest) \
                    in enumerate(tile_iterator(data, blocksize=N_sub,
                                               padsize=Npads,
                                               mode="constant")):
                res_tile = _convolve_sep3_numpy(data_tile.copy(),
                                                hx, hy, hz)
                res[data_s_src] = res_tile[data_s_dest]
            return res


    elif isinstance(data, OCLArray):
        return _convolve_sep3_gpu(data, hx, hy, hz, res_g=res_g, tmp_g = tmp_g)
    else:
        raise TypeError("array argument (1) has bad type: %s" % type(data))