//  [python]
def _get_gga_pass2(mydf, vG, hermi=1, kpts=numpy.zeros((1,3)), verbose=None):
    #if hermi != 1:
    #    raise NotImplementedError('_get_gga_pass2 assumes hermi=1')
    log = logger.new_logger(mydf, verbose)
    cell = mydf.cell
    nkpts = len(kpts)
    nao = cell.nao_nr()
    nx, ny, nz = mydf.mesh
    vG = vG.reshape(-1,4,nx,ny,nz)
    nset = vG.shape[0]

    at_gamma_point = gamma_point(kpts)
    if at_gamma_point:
        veff = numpy.zeros((nset,nkpts,nao,nao))
    else:
        veff = numpy.zeros((nset,nkpts,nao,nao), dtype=numpy.complex128)

    for grids_dense, grids_sparse in mydf.tasks:
        mesh = grids_dense.mesh
        ngrids = numpy.prod(mesh)
        log.debug('mesh %s', mesh)

        gx = numpy.fft.fftfreq(mesh[0], 1./mesh[0]).astype(numpy.int32)
        gy = numpy.fft.fftfreq(mesh[1], 1./mesh[1]).astype(numpy.int32)
        gz = numpy.fft.fftfreq(mesh[2], 1./mesh[2]).astype(numpy.int32)
        #:sub_vG = vG[:,:,gx[:,None,None],gy[:,None],gz].reshape(-1,ngrids)
        sub_vG = _take_5d(vG, (None, None, gx, gy, gz)).reshape(-1,ngrids)
        v_rs = tools.ifft(sub_vG, mesh).reshape(nset,4,ngrids)
        vR = numpy.asarray(v_rs.real, order='C')
        vI = numpy.asarray(v_rs.imag, order='C')
        ignore_vG_imag = hermi == 1 or abs(vI.sum()) < IMAG_TOL
        if ignore_vG_imag:
            v_rs = vR
        elif veff.dtype == numpy.double:
            # ensure result complex array if tddft amplitudes are complex while
            # at gamma point
            veff = veff.astype(numpy.complex128)

        if grids_sparse is None:
            idx_h = grids_dense.ao_idx
            naoh = len(idx_h)
            for ao_h_etc, p0, p1 in mydf.aoR_loop(grids_dense, kpts, deriv=1):
                ao_h = ao_h_etc[0]
                for k in range(nkpts):
                    for i in range(nset):
                        aow = numint._scale_ao(ao_h[k], v_rs[i])
                        v = lib.dot(ao_h[k][0].conj().T, aow)
                        veff[i,k,idx_h[:,None],idx_h] += v
                        if hermi == 1:
                            veff[i,k,idx_h[:,None],idx_h] += v.conj().T
                        else:
                            aow = numint._scale_ao(ao_h[k], v_rs[i].conj())
                            v = lib.dot(aow.conj().T, ao_h[k][0])
                            veff[i,k,idx_h[:,None],idx_h] += v
                ao_h = ao_h_etc = None
        else:
            idx_h = grids_dense.ao_idx
            idx_l = grids_sparse.ao_idx
            # idx_t = numpy.append(idx_h, idx_l)
            naoh = len(idx_h)

            h_cell = grids_dense.cell
            l_cell = grids_sparse.cell
            t_cell = h_cell + l_cell
            t_cell, coeff = t_cell.to_uncontracted_cartesian_basis()
            nshells_h = _pgto_shells(h_cell)
            nshells_t = _pgto_shells(t_cell)

            h_coeff = scipy.linalg.block_diag(*coeff[:h_cell.nbas])
            l_coeff = scipy.linalg.block_diag(*coeff[h_cell.nbas:])
            t_coeff = scipy.linalg.block_diag(*coeff)

            shls_slice = (0, nshells_h, 0, nshells_t)
            vpR = eval_mat(t_cell, vR, shls_slice, 1, 0, 'GGA', kpts)
            vp = vpR = lib.einsum('nkpq,pi,qj->nkij', vpR, h_coeff, t_coeff)
            if not ignore_vG_imag:
                vpI = eval_mat(t_cell, vI, shls_slice, 1, 0, 'GGA', kpts)
                vpI = lib.einsum('nkpq,pi,qj->nkij', vpI, h_coeff, t_coeff)
                vp = numpy.asarray(vpR) + numpy.asarray(vpI) * 1j
            veff[:,:,idx_h[:,None],idx_h] += vp[:,:,:,:naoh]
            veff[:,:,idx_h[:,None],idx_l] += vp[:,:,:,naoh:]
            if hermi == 1:
                veff[:,:,idx_h[:,None],idx_h] += vp[:,:,:,:naoh].conj().transpose(0,1,3,2)
                veff[:,:,idx_l[:,None],idx_h] += vp[:,:,:,naoh:].conj().transpose(0,1,3,2)
            else:
                if not ignore_vG_imag:
                    # eval_mat only supports <nabla i|v|j>. Evaluate <i|v|nabla j>
                    # by conj(<nabla j|conj(v)|>)
                    vp = numpy.asarray(vpR) - numpy.asarray(vpI) * 1j
                veff[:,:,idx_h[:,None],idx_h] += vp[:,:,:,:naoh].conj().transpose(0,1,3,2)
                veff[:,:,idx_l[:,None],idx_h] += vp[:,:,:,naoh:].conj().transpose(0,1,3,2)

            shls_slice = (nshells_h, nshells_t, 0, nshells_h)
            vpR = eval_mat(t_cell, vR, shls_slice, 1, 0, 'GGA', kpts)
            vp = vpR = lib.einsum('nkpq,pi,qj->nkij', vpR, l_coeff, h_coeff)
            if not ignore_vG_imag:
                vpI = eval_mat(t_cell, vI, shls_slice, 1, 0, 'GGA', kpts)
                vpI = lib.einsum('nkpq,pi,qj->nkij', vpI, l_coeff, h_coeff)
                vp = numpy.asarray(vpR) + numpy.asarray(vpI) * 1j
            veff[:,:,idx_l[:,None],idx_h] += vp
            if hermi == 1:
                veff[:,:,idx_h[:,None],idx_l] += vp.conj().transpose(0,1,3,2)
            else:
                if not ignore_vG_imag:
                    vp = numpy.asarray(vpR) - numpy.asarray(vpI) * 1j
                veff[:,:,idx_h[:,None],idx_l] += vp.conj().transpose(0,1,3,2)

    return veff