Beispiel #1
0
def Broaden(options, VV, II):
    """
    Broadening corresponding to Lock in measurements for the
    conductance and IETS spectra. Also resample II, Pow, and nPh
    to match a common voltage list
    """

    II = II.copy()
    II = II.real

    # First derivative dI and bias list dV
    dI = (II[1:len(II)] - II[:-1]) / (VV[1] - VV[0])
    dV = (VV[1:len(VV)] + VV[:-1]) / 2
    # Second derivative and bias ddV
    ddI = (dI[1:len(dI)] - dI[:-1]) / (VV[1] - VV[0])
    ddV = (dV[1:len(dV)] + dV[:-1]) / 2

    # Modulation amplitude
    VA = N.sqrt(2.0) * options.Vrms

    # New bias ranges for broadening
    tmp = int(N.floor(VA / (dV[1] - dV[0])) + 1)
    BdV = dV[tmp:-tmp]
    BddV = ddV[tmp:-tmp]

    # Initiate derivatives
    BdI = 0 * BdV
    BddI = 0 * BddV

    # Calculate first derivative with Vrms broadening
    for iV, V in enumerate(BdV):
        SIO.printDone(iV, len(BdV),
                      'Inelastica.Broaden: First-derivative Vrms broadening')
        wt = (N.array(range(200)) / 200.0 - 0.5) * N.pi
        VL = V + VA * N.sin(wt)
        dIL = MM.interpolate(VL, dV, dI)
        BdI[iV] = 2 / N.pi * N.sum(dIL * (N.cos(wt)**2)) * (wt[1] - wt[0])

    # Calculate second derivative with Vrms broadening
    for iV, V in enumerate(BddV):
        SIO.printDone(iV, len(BddV),
                      'Inelastica.Broaden: Second-derivative Vrms broadening')
        wt = (N.array(range(200)) / 200.0 - 0.5) * N.pi
        VL = V + VA * N.sin(wt)
        ddIL = MM.interpolate(VL, ddV, ddI)
        BddI[iV] = 8.0 / 3.0 / N.pi * N.sum(ddIL *
                                            (N.cos(wt)**4)) * (wt[1] - wt[0])

    # Reduce to one voltage grid
    NN = options.biasPoints
    V = N.linspace(options.minBias, options.maxBias, NN)

    NI = MM.interpolate(V, VV, II)
    NdI = MM.interpolate(V, dV, dI)
    NddI = MM.interpolate(V, ddV, ddI)
    NBdI = MM.interpolate(V, BdV, BdI)
    NBddI = MM.interpolate(V, BddV, BddI)

    return V, NI, NdI, NddI, NBdI, NBddI
Beispiel #2
0
    def pointGroup(self):
        from itertools import product as iprod
        import numpy.linalg as LA
        # Find the symmetry operators and centers where the basis is unchanged

        # Use the least common siesta atom type to find possible centers
        abundance = [N.sum(N.array(self.basis.snr) == snr) for snr in self.basis.snr]
        whichsnr = self.basis.snr[N.where(N.array(abundance) == N.min(abundance))[0][0]]

        Ulist, a1, a2, a3 = self.pointU33, self.a1, self.a2, self.a3
        pointU,  pointO = [],  []
        for iU, U in enumerate(Ulist):
            SIO.printDone(iU, len(Ulist), 'Looking for point group')

            xyz = self.basis.xyz[N.where(self.basis.snr == whichsnr)[0]]
            # Find centers by solving U(x_i-o)==x_j-o +R where o is center, R is lattice vector
            centers = []
            A = U-N.eye(3)
            for i1, i2, i3 in iprod(range(-1, 2), repeat=3):
                for ii, jj in iprod(range(len(xyz)), repeat=2):
                    sol = LA.lstsq(A, mm(U, xyz[ii, :].transpose())-xyz[jj, :].transpose()+(a1*i1+a2*i2+a3*i3))[0]
                    correct = not N.any(N.abs(mm(A, sol)-mm(U, xyz[ii, :].transpose())+xyz[jj, :].transpose()-(a1*i1+a2*i2+a3*i3)) > 1e-6)
                    if correct: centers += [sol]
            centers = myUnique2(moveIntoCell(N.array(centers), a1, a2, a3, self.accuracy), self.accuracy)
            # All centers are not correct since we only looked at one atom type and
            # remove repeats of the same symmetry by looking at ipvi, i.e., which atom moves onto which
            origin, ipiv = [], []
            for o in centers:
                xyz, nxyz = self.basis.xyz, mm(U, self.basis.xyz.transpose()-o.reshape((3, 1))).transpose()+o
                xyz, nxyz = moveIntoCell(xyz, a1, a2, a3, self.accuracy), moveIntoCell(nxyz, a1, a2, a3, self.accuracy)
                thisipiv = []
                for x in xyz:
                    for iy, y in enumerate(nxyz):
                        if N.allclose(x, y, atol=self.accuracy):
                            thisipiv += [iy]

                trueSym = len(thisipiv) == self.basis.NN and N.allclose(N.array(self.basis.snr)[thisipiv], self.basis.snr) and N.allclose(N.sort(thisipiv), N.arange(self.basis.NN))
                if trueSym and len(myIntersect(N.array(ipiv), N.array([thisipiv]), self.accuracy)) == 0:
                    origin, ipiv = origin+[o], ipiv+[thisipiv]
            if len(origin) > 0:
                pointU += [U]
                pointO += [origin]

        self.U33, self.origo = pointU, pointO
        print("Symmetry: %i point symmetry operations (with rotation centers) found for lattice+basis."%len(pointU))

        # Calculate rank of operations
        self.rankU33, sign = [], []
        for U in self.U33:
            tmp, ii = U, 1
            while ii < 7 and not N.allclose(N.eye(3), tmp, atol=self.accuracy):
                tmp, ii = mm(tmp, U), ii+1
            if ii > 6: sys.exit('Symmetry error: rank >6 !!')
            self.rankU33 += [ii]
            sign += [N.linalg.det(U)]
        print "Symmetry: rank*det"
        print N.array(self.rankU33)*sign
        return
Beispiel #3
0
def writeFGRrates(options, GF, hw, NCfile):
    print 'Inelastica.writeFGRrates: Computing FGR rates'
    # Eigenchannels
    GF.calcEigChan(channels=options.numchan)
    NCfile = NC4.Dataset(options.PhononNetCDF, 'r')
    print 'Reading ', options.PhononNetCDF

    outFile = file('%s/%s.IN.FGR'%(options.DestDir, options.systemlabel), 'w')
    outFile.write('Total transmission [in units of (1/s/eV)] : %e\n' % (PC.unitConv*GF.TeF,))

    for ihw in range(len(hw)):
        SIO.printDone(ihw, len(hw), 'Golden Rate')
        M = N.array(NCfile.variables['He_ph'][ihw, options.iSpin, :, :], N.complex)
        try:
            M += 1.j*N.array(NCfile.variables['ImHe_ph'][ihw, options.iSpin, :, :], N.complex)
        except:
            print 'Warning: Variable ImHe_ph not found'
        rate=N.zeros((len(GF.ECleft), len(GF.ECright)), N.float)
        totrate=0.0
        inter, intra = 0.0, 0.0 # splitting total rate in two
        for iL in range(len(GF.ECleft)):
            for iR in range(len(GF.ECright)):
                tmp=N.dot(N.conjugate(GF.ECleft[iL]), MM.mm(M, GF.ECright[iR]))
                rate[iL, iR]=(2*N.pi)**2*abs(tmp)**2
                totrate+=rate[iL, iR]
                if iL==iR: intra += rate[iL, iR]
                else: inter += rate[iL, iR]

        outFile.write('\nPhonon mode %i : %f eV [Rates in units of (1/s/eV)]\n' % (ihw, hw[ihw]))
        outFile.write('eh-damp : %e (1/s) , heating %e (1/(sV)))\n' % (GF.P1T[ihw]*PC.unitConv*hw[ihw], GF.P2T[ihw]*PC.unitConv))
        outFile.write('eh-damp 1, 2 (MALMAL, MARMAR): %e (1/s) , %e (1/(s)))\n' % (GF.ehDampL[ihw]*PC.unitConv*hw[ihw], GF.ehDampR[ihw]*PC.unitConv*hw[ihw]))
        outFile.write('SymI : %e (1/(sV)) , AsymI %e (?))\n' % (GF.nHT[ihw]*PC.unitConv, GF.HT[ihw]*PC.unitConv))
        #outFile.write('Elast : %e (1/(sV)) , Inelast %e (1/(sV)))\n' % (GF.nHTel[ihw]*PC.unitConv,GF.nHTin[ihw]*PC.unitConv))
        outFile.write('down=left EC, right=right EC\n')
        if GF.P2T[ihw]>0.0:
            if abs(totrate/(GF.P2T[ihw])-1)<0.05:
                outFile.write('Sum/Tr[MALMAR] , Tr: %1.3f  %e\n'%(totrate/(GF.P2T[ihw]), PC.unitConv*GF.P2T[ihw]))
            else:
                outFile.write('WARNING: !!!! Sum/Tr[MALMAR] , Tr: %2.2e  %e\n'%(totrate/(GF.P2T[ihw]), PC.unitConv*GF.P2T[ihw]))
        else:
            outFile.write(' Tr:  %e\n'%(PC.unitConv*GF.P2T[ihw]))
        inter = inter/GF.P2T[ihw]
        intra = intra/GF.P2T[ihw]
        outFile.write('Interchannel ratio: Sum(inter)/Tr[MALMAR]      = %.4f \n'%inter)
        outFile.write('Intrachannel ratio: Sum(intra)/Tr[MALMAR]      = %.4f \n'%intra)
        outFile.write('Inter+intra ratio: Sum(inter+intra)/Tr[MALMAR] = %.4f \n'%(inter+intra))
        for iL in range(len(GF.ECleft)):
            for iR in range(len(GF.ECright)):
                outFile.write('%e ' % (PC.unitConv*rate[iL, iR],))
            outFile.write('\n')
    outFile.close()
Beispiel #4
0
def calcFS(ispin):
    # Calculate Fermi-surface
    NNk = general.NNk
    bands = N.zeros((NNk, NNk, NNk, HS.N), N.float)
    for ix in range(general.NNk):
        for iy in range(general.NNk):
            for iz in range(general.NNk):
                # "unitless" k-vect
                kpnt = N.array([ix, iy, iz], N.float) / float(NNk - 1)
                HS.setkpoint(kpnt)
                eival = LA.eigvals(mm(LA.inv(HS.S), HS.H[ispin, :, :]))
                ipiv = N.argsort(eival)
                bands[ix, iy, iz, :] = eival[ipiv]
        SIO.printDone(ix, NNk, 'Fermi Surface: ')
    writeFS(ispin, NNk, bands)
Beispiel #5
0
def calcFS(ispin):
    # Calculate Fermi-surface
    NNk = 31
    bands = N.zeros((NNk, NNk, NNk, HS.N), N.float)
    for ix in range(NNk):
        for iy in range(NNk):
            for iz in range(NNk):
                # "unitless" k-vect
                kpnt = N.array([ix, iy, iz], N.float) / float(NNk - 1)
                HS.setkpoint(kpnt, verbose=False)
                eival = SLA.eigh(HS.H[ispin], HS.S, eigvals_only=True)
                ipiv = N.argsort(eival)
                bands[ix, iy, iz, :] = eival[ipiv]
        SIO.printDone(ix, NNk, 'Fermi Surface: ')
    writeFS(ispin, NNk, bands)
Beispiel #6
0
def calcWF(options, geom, basis, Y):
    """
    Calculate wavefunction, returns:
    YY : complex wavefunction on regular grid
    dstep : stepsize
    origo : vector
    nx, ny, nz : number of grid points
    """

    xyz = N.array(geom.xyz[options.DeviceAtoms[0] - 1:options.DeviceAtoms[1]])

    # Size of cube
    xmin, xmax = min(xyz[:, 0]) - 5.0, max(xyz[:, 0]) + 5.0
    ymin, ymax = min(xyz[:, 1]) - 5.0, max(xyz[:, 1]) + 5.0
    zmin, zmax = min(xyz[:, 2]) - 5.0, max(xyz[:, 2]) + 5.0
    xl, yl, zl = xmax - xmin, ymax - ymin, zmax - zmin
    dx, dy, dz = options.res, options.res, options.res
    nx, ny, nz = int(xl / dx) + 1, int(yl / dy) + 1, int(zl / dz) + 1

    origo = N.array([xmin, ymin, zmin], N.float)

    # Def cube
    YY = N.zeros((nx, ny, nz), N.complex)
    rx = N.array(list(range(nx)), N.float) * dx + origo[0]
    ry = N.array(list(range(ny)), N.float) * dy + origo[1]
    rz = N.array(list(range(nz)), N.float) * dz + origo[2]

    for ii, Yval in enumerate(Y):
        if ii > 0:  # and ii%(int(len(Y)/10)) == 0:
            SIO.printDone(ii, len(Y), 'Wavefunction')

        rax, ray, raz = basis.xyz[ii, 0], basis.xyz[ii, 1], basis.xyz[ii, 2]
        # Only calulate in subset
        ixmin, ixmax = int((rax-origo[0]-basis.coff[ii])/dx), \
                       int((rax-origo[0]+basis.coff[ii])/dx)
        iymin, iymax = int((ray-origo[1]-basis.coff[ii])/dy), \
                       int((ray-origo[1]+basis.coff[ii])/dy)
        izmin, izmax = int((raz-origo[2]-basis.coff[ii])/dz), \
                       int((raz-origo[2]+basis.coff[ii])/dz)

        ddx, ddy, ddz = rx[ixmin:ixmax] - rax, ry[iymin:iymax] - ray, rz[
            izmin:izmax] - raz

        dr = N.sqrt(MM.outerAdd(ddx * ddx, ddy * ddy, ddz * ddz))
        drho = N.sqrt(MM.outerAdd(ddx * ddx, ddy * ddy, 0 * ddz))

        imax = (basis.coff[ii] - 2 * basis.delta[ii]) / basis.delta[ii]
        ri = dr / basis.delta[ii]
        ri = N.where(ri < imax, ri, imax)
        ri = ri.astype(N.int)
        costh = MM.outerAdd(0 * ddx, 0 * ddy, ddz) / dr
        cosfi, sinfi = MM.outerAdd(ddx, 0 * ddy, 0 * ddz) / drho, MM.outerAdd(
            0 * ddx, ddy, 0 * ddz) / drho

        # Numpy has changed the choose function to crap!
        RR = N.take(basis.orb[ii], ri)

        # Calculate spherical harmonics
        l = basis.L[ii]
        m = basis.M[ii]
        if l == 3:
            print('f-shell : l=%i, m=%i (NOT TESTED!!)' % (l, m))
        thisSphHar = MM.sphericalHarmonics(l, m, costh, sinfi, cosfi)

        YY[ixmin:ixmax, iymin:iymax, izmin:izmax] = YY[ixmin:ixmax, iymin:iymax, izmin:izmax]+\
                                                    RR*thisSphHar*Yval

    print("Wave function norm on real space grid:",
          N.sum(YY.conjugate() * YY) * dx * dy * dz)

    return YY, options.res, origo, nx, ny, nz
    def symmetrizeFC(self, FC, FCfirst, FClast, radi=0.0):
        NN, NU, NFC = self.NN, len(self.U33), FClast - FCfirst + 1
        if self.basis.NN > NFC:
            print "Phonons: ERROR: FCfirst/last do contain all atoms in the basis (%i)." % self.basis.NN
            sys.exit('Symmetry error:')

        # Rearrange to FC_ia,jb, force from atom j, axis b to atom i, axis a
        if len(FC.shape) == 3:
            FCreshape = True
            FCn = N.zeros((NFC, 3, self.NN, 3))
            for ii in range(NFC):
                for jj in range(3):
                    FCn[ii, jj, :, :] = FC[ii * 3 + jj, :, :]
            FC = FCn
        else:
            FCreshape = False

        # Rearange basis to fit FCfirst...FClast order in Siesta FC file
        basisxyz = moveIntoCell(self.xyz[FCfirst-1:FClast],\
                                self.a1, self.a2, self.a3, self.accuracy)
        ipiv = []
        for elem in basisxyz[0:FClast - FCfirst + 1]:
            for jj, comp in enumerate(self.basis.xyz):
                if N.allclose(elem, comp, atol=self.accuracy):
                    ipiv += [jj]
                    break
        if len(N.unique(ipiv)) != self.basis.NN:
            print "Symmetry: Some confusion about the order of the basis of atoms and the FCfirst/last region."
            sys.exit('Symmetry: This should never happen')
        self.basis.xyz = self.basis.xyz[ipiv, :]
        self.basis.snr, self.basis.anr = N.array(
            self.basis.snr)[ipiv], N.array(self.basis.anr)[ipiv]

        # Find out which basis atom corresponds to each atom
        xyz = moveIntoCell(self.xyz, self.a1, self.a2, self.a3, self.accuracy)
        self.basisatom = N.zeros((self.NN), N.int)
        for ii in range(self.basis.NN):
            indx = N.where(
                N.sum(N.abs(xyz -
                            self.basis.xyz[ii, :]), axis=1) < self.accuracy)
            self.basisatom[indx[0]] = ii

        # Symmetry operations are complicated by the periodic structure
        # in the Siesta calculation. So ... limit range of interaction.

        # Find radie and center for biggest sphere fitting into pbc
        if radi == 0.0:
            radi = findRadi(self.pbc[0], self.pbc[1], self.pbc[2])*\
                (1-5*self.accuracy)
        print "Symmetry: Longest range of forces %f Ang." % radi

        # Symmetry operation on FC is composed of:
        #     FC_ia,jb = U^t_aa' PL^j_ii' FC_i'a',j'b' PR_j'j UR_b'b
        # (where 'ed are summed). I.e., normal matrix mult for the L/R
        # unitary matrices. The permutation matrices are complicated.
        # PR : U may change which atom in the basis is moved.
        # PL : Should point to the atom closest to the atom moved and
        #      thus may depend also on j, i.e., the atom moved

        UL = [N.transpose(self.U33[ii]) for ii in range(NU)]
        UR = [self.U33[ii] for ii in range(NU)]
        PL = N.zeros((NU, NFC, NN, NN), N.int)
        PR = N.zeros((NU, NFC), N.int)
        for iU in range(NU):
            for ii in range(NFC):
                SIO.printDone(iU * NFC + ii, NU * NFC, 'Symmetrizing')

                # Figure out which atoms are connected by symmetry op.
                xyz = self.xyz.copy() - self.origo[iU]
                FCxyz = xyz[FCfirst - 1 + ii, :].copy()
                xyz = moveIntoClosest(N.array(xyz)-FCxyz,\
                                    self.pbc[0], self.pbc[1], self.pbc[2])+FCxyz
                nxyz = N.transpose(mm(self.U33[iU], N.transpose(xyz)))
                # Did the moving atom move between unit cells?
                nFCxyz, iix = nxyz[FCfirst - 1 + ii, :].copy(), 10
                for ix in range(-3, 4):
                    for iy in range(-3, 4):
                        for iz in range(-3, 4):
                            if N.any(
                                    N.sum(N.abs(nFCxyz + ix * self.a1 +
                                                iy * self.a2 + iz * self.a3 -
                                                xyz[FCfirst - 1:FClast]),
                                          axis=1) < self.accuracy):
                                iix, iiy, iiz = ix, iy, iz
                if iix == 10: sys.exit('Symmetry Error')
                tFCxyz = nFCxyz + iix * self.a1 + iiy * self.a2 + iiz * self.a3
                shift = tFCxyz - nFCxyz  # Shift all new coordinates
                nxyz = moveIntoClosest(N.array(nxyz)+shift-FCxyz,\
                                    self.pbc[0], self.pbc[1], self.pbc[2])+FCxyz

                # Which atoms are within radi?
                indx = N.where(distance(xyz - FCxyz) < radi)[0]

                # Find the target atom
                diff = N.sum(N.abs(nxyz[indx].reshape((-1, 1, 3))-\
                         xyz.reshape((1, -1, 3))), axis=2)<self.accuracy
                tindx = N.where(diff)
                tindx2 = tindx[1]
                indx3 = indx[tindx[0]]
                if len(indx3) != len(indx):
                    for ix in range(-1, 2):
                        for iy in range(-1, 2):
                            for iz in range(-1, 2):
                                if ix != 0 or iy != 0 or iz != 0:
                                    tindxs = N.where(N.sum(N.abs(nxyz[indx].reshape((-1, 1, 3))+\
                                                                  self.pbc[0]*ix+self.pbc[1]*iy+self.pbc[2]*iz-\
                                                                  xyz.reshape((1, -1, 3))), axis=2)<self.accuracy)
                                    indx3 = N.concatenate(
                                        (indx3, indx[tindxs[0]]))
                                    tindx2 = N.concatenate((tindx2, tindxs[1]))
                if len(indx3) != len(indx):
                    sys.exit('Symmetry error')
                # Make permutation matrix
                PL[iU, ii, tindx2, indx3] = 1
                indx2 = N.where(distance(xyz - tFCxyz) < self.accuracy)
                PR[iU, ii] = self.basisatom[indx2[0]]

                # TF: Check that the symmetry operations apply to FC??
                for kk in range(len(indx3)):
                    oFC = FC[ii, :, indx3[kk], :].reshape((3, 3))
                    sFC = mm(UL[iU], FC[indx2[0], :, tindx2[kk], :].reshape(
                        (3, 3)), UR[iU])
                    if N.max(N.abs(oFC - sFC)) > 0.5:
                        print oFC
                        print sFC

        def applySym(FC):
            FCn = N.tensordot(UR[iU], FC, ((1, 1)))
            FCn = N.swapaxes(FCn, 0, 1)
            FCn = N.tensordot(FCn, UL[iU], ((3, 0)))
            FCn2 = 0 * FCn
            for ii in range(NFC):
                tmp = N.tensordot(PL[iU, ii, :, :], \
                                      FCn[ii, :, :, :], ((1, 1)))
                tmp = N.swapaxes(tmp, 0, 1)
                FCn2[PR[iU, ii], :, :, :] = tmp
            return FCn2

        # Symmetrize dynamical matrix
        print "Symmetry: Iterative application of symmetries"
        niter, change = 0, 10
        FCo = FC.copy()
        # Uncomment the two lines below to skip the application of symmetries
        #niter, change = 10, 10
        #FCs = FC.copy()
        while niter < 10 and change > 1e-10:
            FCs = FCo
            for iU in range(NU):
                FCn = FCs
                FCs = 0
                for jj in range(self.rankU33[iU]):
                    FCn = applySym(FCn)
                    FCs += FCn
                FCs = FCs / self.rankU33[iU]

            change = N.max(N.abs(FCs - FCo))
            print "Symmetry: max change between old and symmetrized = %e" % change
            print "Symmetry: relative change = %e\n" % (
                N.max(N.abs(FCs - FCo)) / N.max(abs(FCo)))
            FCo = FCs
        if N.max(N.abs(FCs - FC)) / N.max(abs(FC)) > 0.05:
            print "Symmetry: WARNING: large relative difference"

        # Change format back ...
        if FCreshape:
            FC = N.zeros((NFC * 3, self.NN, 3))
            for ii in range(NFC):
                for jj in range(3):
                    FC[ii * 3 + jj, :, :] = FCs[ii, jj, :, :]
            FCs = FC

        return FCs
Beispiel #8
0
def calcWF2(options, geom, DeviceAtoms, basis, Y, NN, Fold=True, k=[0, 0, 0], a=None, fn=''):
    """
    Calculate wavefunction on real space mesh with optional folding
    of the periodic boundary conditions. If Fold==True the vectors 'a'
    will be choosen to be the periodic boundary condition vectors and
    the real space wavefunction folded into the cell using the k-vector.
    If Folded==False, you can choose any 'a' but folding by the PBC will
    not be done.
    Note: Folding assumes coupling only between N.N. cells

    INPUT:
      geom        : MakeGeom structure for full geometry
      DeviceAtoms : [first, last] numbering from 1 to N
      basis       : Basis struct for ONLY the device region
      Y           : Wavefunction for the device region
      NN          : [N1,N2,N3,minN3,maxN3] number of points along [a1, a2, a3]
                    only calculate from minN3 to maxN3
      Fold        : fold periodic boundary conditions
      k           : k-vector to use for folding [-0.5,0.5]
      a           : if Fold==True, uses geom.pbc, if false: [a1, a2, a3]
                    along these directions, i.e., da1=a1/N1 ...

    RETURNS:
    YY : complex wavefunction as N1, N2, N3 matrix
    """
    xyz=N.array(geom.xyz[DeviceAtoms[0]-1:DeviceAtoms[1]])
    N1, N2, N3, minN3, maxN3 = NN[0], NN[1], NN[2], NN[3], NN[4]
    NN3 = maxN3-minN3+1
    if Fold:
        da1, da2, da3 = geom.pbc[0]/N1, geom.pbc[1]/N2, geom.pbc[2]/N3
    else:
        da1, da2, da3 = a[0]/N1, a[1]/N2, a[2]/N3
    try:
        NNY=Y.shape[1]
    except:
        NNY=1
    # Def cube
    YY=[N.zeros((N1, N2, NN3), N.complex) for ii in range(NNY)]
    # Help indices
    i1 = MM.outerAdd(N.arange(N1), N.zeros(N2), N.zeros(NN3))
    i2 = MM.outerAdd(N.zeros(N1), N.arange(N2), N.zeros(NN3))
    i3 = MM.outerAdd(N.zeros(N1), N.zeros(N2), N.arange(NN3)+minN3)

    # Positions x,y,z for points in matrix form
    rx = i1*da1[0]+i2*da2[0]+i3*da3[0]
    ry = i1*da1[1]+i2*da2[1]+i3*da3[1]
    rz = i1*da1[2]+i2*da2[2]+i3*da3[2]

    if Fold:
        pbc = N.array([da1*N1, da2*N2, da3*N3])
        orig = da3*minN3
        b = N.transpose(LA.inv(pbc))
        olist = [orig, orig+pbc[0]+pbc[1]+pbc[2]]
        pairs = N.array([[b[1], b[2]], [b[0], b[2]], [b[0], b[1]]])
        pbcpairs = N.array([[pbc[1], pbc[2]], [pbc[0], pbc[2]], [pbc[0], pbc[1]]])

    for iiatom in range(DeviceAtoms[1]-DeviceAtoms[0]+1):
        if iiatom>0:
            #Wavefunction percent done...
            SIO.printDone(iiatom, DeviceAtoms[1]-DeviceAtoms[0]+1, 'Wave function')

        if not Fold:
            shiftvec = [0, 0, 0]
        else: # include shift vectors if sphere cuts planes of PBC
            basisindx = N.where(basis.ii==iiatom+DeviceAtoms[0])[0]
            basisradius = N.max(basis.coff[basisindx])
            minshift, maxshift = [0, 0, 0], [0, 0, 0]
            for iithiso, thiso in enumerate(olist):
                c=xyz[iiatom, :]-thiso
                for ip in range(3):
                    n = N.cross(pbcpairs[ip, 0], pbcpairs[ip, 1])
                    n = n / LA.norm(n)
                    dist = N.abs(N.dot(n, N.dot(N.dot(pairs[ip], c), pbcpairs[ip])-c))
                    if dist < basisradius:
                        if iithiso==0:
                            minshift[ip]=-1
                        else:
                            maxshift[ip]=1
            shiftvec = []
            for ix in range(minshift[0], maxshift[0]+1):
                for iy in range(minshift[1], maxshift[1]+1):
                    for iz in range(minshift[2], maxshift[2]+1):
                        shiftvec+=[[ix, iy, iz]]

        #print(shiftvec)
        for shift in shiftvec:
            # Atom position shifted
            vec=-N.dot(N.array(shift), geom.pbc)
            phase = N.exp(-1.0j*(2*N.pi*N.dot(N.array(k), N.array(shift))))

            # Difference and polar, cylinder distances
            dx, dy, dz=rx-xyz[iiatom, 0]-vec[0], ry-xyz[iiatom, 1]-vec[1], rz-xyz[iiatom, 2]-vec[2]
            dr2=dx*dx+dy*dy+dz*dz
            drho2=dx*dx+dy*dy

            basisindx = N.where(basis.ii==iiatom+DeviceAtoms[0])[0]
            old_coff, old_delta = 0.0, 0.0
            for basisorb in basisindx:
                if not (basis.coff[basisorb]==old_coff and basis.delta[basisorb]==old_delta):
                    old_coff, old_delta = basis.coff[basisorb], basis.delta[basisorb]
                    indx = N.where(dr2<basis.coff[basisorb]**2) # Find points close to atom

                    idr, idrho=N.sqrt(dr2[indx]), N.sqrt(drho2[indx])
                    iri=(idr/basis.delta[basisorb]).astype(N.int)
                    idx, idy, idz = dx[indx], dy[indx], dz[indx]

                    costh = idz/idr
                    cosfi, sinfi = idx/idrho, idy/idrho

                    # Fix divide by zeros
                    indxRzero, indxRhozero = N.where(idr==0.0), N.where(idrho==0.0)
                    costh[indxRzero] = 1.0
                    cosfi[indxRhozero], sinfi[indxRhozero] = 1.0, 0.0

                    # Numpy has changed the choose function to crap!
                    RR=N.take(basis.orb[basisorb], iri)
                # Calculate spherical harmonics
                if len(idr)>0:
                    l = basis.L[basisorb]
                    m = basis.M[basisorb]
                    if l==3:
                        print('f-shell : l=%i, m=%i (NOT TESTED!!)'%(l, m))
                    thisSphHar = MM.sphericalHarmonics(l, m, costh, sinfi, cosfi)
                    for iy in range(NNY):
                        YY[iy][indx]=YY[iy][indx]+RR*thisSphHar*Y[basisorb, iy]*phase
    N1, N2, N3, minN3, maxN3 = NN[0], NN[1], NN[2], NN[3], NN[4]
    for ii in range(NNY):
        writenetcdf2(geom, fn+'%i.nc'%ii, YY[ii], N1, N2, N3, minN3, maxN3, geom.pbc, options.DeviceAtoms)
    return YY