def chgcarBondAnalysis(chgcarfile,
                       bondLengths,
                       normalize=False,
                       verbose=False):

    BLs = bondLengths
    nBLs = len(BLs)

    #Parse CHGCAR
    chgcar = open(chgcarfile, "r").readlines()
    (v1, v2, v3, atypes, axs, ays, azs,
     header), gridSize, chg = chgcarIO.read(chgcar)
    basis = asarray([v1, v2, v3])
    lengths = array([v1[0], v2[1], v3[2]])
    atoms = array(zip(axs, ays, azs))

    #Grid properties
    nGridPoints = reduce(operator.mul, gridSize)

    #Neighbors
    halfNeighbors = voronoiNeighbors(atoms, basis, atypes, style='half')

    a = chg.shape
    AvgChg = sum([sum([sum(line) for line in plane])
                  for plane in chg]) / a[0] / a[1] / a[2]
    if verbose:
        print "Average CHG value:", AvgChg

    #Evaluate the CHG between each nieghbor pair
    avgchgline, xchglines, ychglines, halfNeighbors = fieldNeighbors1D(
        atoms, atypes, basis, chg, gridSize, halfNeighbors)

    #Cutoff neighbors that fall below the thresh-hold
    Ninterp = len(avgchgline)
    avgIBL = zeros([nBLs, Ninterp])  #avg line inside the bond length
    avgOBL = zeros([nBLs, Ninterp])  #avg line outside the bond length
    nibl = zeros(nBLs)
    nobl = zeros(nBLs)

    cnt = 0
    for a, jNeighbors in enumerate(halfNeighbors):
        atoma = atoms[a]
        for b, jNeighb in enumerate(jNeighbors):
            atomb = atoms[jNeighb]
            d = dist_periodic(atoma, atomb, lengths)
            vals = ychglines[a][b]
            xx = xchglines[a][b]
            for j, bl in enumerate(BLs):
                if normalize:
                    avals = array(vals) / AvgChg
                else:
                    avals = array(vals)
                if d < bl:
                    nibl[j] += 2
                    avgIBL[j] += avals
                    avgIBL[j] += avals[::-1]
                else:
                    cnt += 1
                    nobl[j] += 2
                    avgOBL[j] += avals
                    avgOBL[j] += avals[::-1]
    for i in range(nBLs):
        if nibl[i] == 0:
            nibl[i] = 1
        if nobl[i] == 0:
            nobl[i] = 1
    avgOBL = [avgOBL[i] / nobl[i] for i in range(nBLs)]
    avgIBL = [avgIBL[i] / nibl[i] for i in range(nBLs)]
    return avgOBL, nobl, avgIBL, nibl
ay=atoms[:,1]
az=atoms[:,2]
types=[0]*atypes[0]
fig=mlab.figure(bgcolor=(1.0,1.0,1.0))

rlen=list()
soft=list()
s2=list()
mxSoft=0
mnSoft=10
mxLen=0
mnLen=10
for i in range(nIon):
    s2.append(list())
    for j in neighbs[i]:
        r=dist_periodic(atoms[i],atoms[j],lengths)

        #g(E,atomi)
        ga=occGrid[i][uBounds]
        gb=occGrid[j][uBounds]
        #soft.append(sum(ga*gb)/d/delU*2)
        soft.append(sum(ga+gb)/delU)
        s2[-1].append(sum(ga+gb)/delU)
        mxSoft=max(mxSoft,soft[-1])
        mnSoft=min(mnSoft,soft[-1])
        rlen.append(r)
        if r<3.2:
            mxLen=max(mxLen,rlen[-1])
            mnLen=min(mnLen,rlen[-1])
mnSoft,mxSoft=0.15,4.0
mnLen,mxLen = 2.40,2.9
def chgcarBondAnalysis(chgcarfile,bondLengths,normalize=False,verbose=False):

    BLs=bondLengths
    nBLs=len(BLs)

    #Parse CHGCAR
    chgcar=open(chgcarfile,"r").readlines()
    (v1,v2,v3,atypes,axs,ays,azs,header),gridSize,chg = chgcarIO.read(chgcar)
    basis=asarray([v1,v2,v3])
    lengths=array([v1[0],v2[1],v3[2]])
    atoms=array(zip(axs,ays,azs))

    #Grid properties
    nGridPoints=reduce(operator.mul,gridSize)

    #Neighbors
    halfNeighbors=voronoiNeighbors(atoms,basis,atypes,style='half')

    a=chg.shape
    AvgChg=sum([sum([sum(line) for line in plane]) for plane in chg])/a[0]/a[1]/a[2]
    if verbose:
        print "Average CHG value:",AvgChg

    #Evaluate the CHG between each nieghbor pair
    avgchgline,xchglines,ychglines,halfNeighbors=fieldNeighbors1D(atoms,atypes,basis,chg,gridSize,halfNeighbors)

    #Cutoff neighbors that fall below the thresh-hold
    Ninterp=len(avgchgline)
    avgIBL=zeros([nBLs,Ninterp]) #avg line inside the bond length
    avgOBL=zeros([nBLs,Ninterp]) #avg line outside the bond length
    nibl=zeros(nBLs)
    nobl=zeros(nBLs)

    cnt=0
    for a,jNeighbors in enumerate(halfNeighbors):
        atoma=atoms[a]
        for b,jNeighb in enumerate(jNeighbors):
            atomb=atoms[jNeighb]
            d=dist_periodic(atoma,atomb,lengths)
            vals=ychglines[a][b]
            xx=xchglines[a][b]
            for j,bl in enumerate(BLs):
                if normalize:
                    avals=array(vals)/AvgChg
                else:
                    avals=array(vals)
                if d<bl:
                    nibl[j]+=2
                    avgIBL[j]+=avals
                    avgIBL[j]+=avals[::-1]
                else:
                    cnt+=1
                    nobl[j]+=2
                    avgOBL[j]+=avals
                    avgOBL[j]+=avals[::-1]
    for i in range(nBLs):
        if nibl[i]==0:
            nibl[i]=1
        if nobl[i]==0:
            nobl[i]=1
    avgOBL=[avgOBL[i]/nobl[i] for i in range(nBLs)]
    avgIBL=[avgIBL[i]/nibl[i] for i in range(nBLs)]
    return avgOBL,nobl,avgIBL,nibl
ay = atoms[:, 1]
az = atoms[:, 2]
types = [0] * atypes[0]
fig = mlab.figure(bgcolor=(1.0, 1.0, 1.0))

rlen = list()
soft = list()
s2 = list()
mxSoft = 0
mnSoft = 10
mxLen = 0
mnLen = 10
for i in range(nIon):
    s2.append(list())
    for j in neighbs[i]:
        r = dist_periodic(atoms[i], atoms[j], lengths)

        #g(E,atomi)
        ga = occGrid[i][uBounds]
        gb = occGrid[j][uBounds]
        #soft.append(sum(ga*gb)/d/delU*2)
        soft.append(sum(ga + gb) / delU)
        s2[-1].append(sum(ga + gb) / delU)
        mxSoft = max(mxSoft, soft[-1])
        mnSoft = min(mnSoft, soft[-1])
        rlen.append(r)
        if r < 3.2:
            mxLen = max(mxLen, rlen[-1])
            mnLen = min(mnLen, rlen[-1])
mnSoft, mxSoft = 0.15, 4.0
mnLen, mxLen = 2.40, 2.9
def fieldNeighbors1D(atoms,atypes,basis,field,halfNeighbors=None,Ninterp=50):
    [v1,v2,v3]=basis
    latoms=array(atoms)

    #Ensure simulation box is orthorhombic
    if sum(map(fabs,v1))-fabs(v1[0]) > 1e-10 or \
       sum(map(fabs,v2))-fabs(v2[1]) > 1e-10 or \
       sum(map(fabs,v3))-fabs(v3[2]) > 1e-10:
        print "Error: simulation axes are not sufficiently orthogonal.  Use script poscarRectify.py and regenerate doscar"
        exit(0)
    
    bounds=[[0.,v1[0]],[0.,v2[1]],[0.,v3[2]]]
    simSize=asarray([v1[0],v2[1],v3[2]])

    if halfNeighbors==None:
        halfNeighbors=voronoiNeighbors(atoms=latoms,basis=basis,atypes=atypes,style='half')

    #Interpolation and summation properties
    xlines=list()
    ylines=list()
    avgyline=zeros(Ninterp)
    nlines=float(sum(map(len,halfNeighbors)))

    #Local Grid size
    fieldSize=elf.size
    delGrids=simSize/fieldSize
    lGridSize=fieldSize
    nlGridPoints=reduce(operator.mul,lGridSize)
    for iNeighb,jNeighbors in enumerate(halfNeighbors):
        xlines.append(list())
        ylines.append(list())
        if len(jNeighbors)==0:
            continue

        atomi=latoms[iNeighb]
        for i,ai in enumerate(atomi):
            if ai < 0.0:
                atomi[i]+=simSize[i]
            if ai > simSize[i]:
                atomi[i]-=simSize[i]

        lGridCenter = map(int,atomi/simSize*fieldSize)
        lGridBounds = [[lGridCenter[i]-lGridSize[i]/2,lGridCenter[i]+lGridSize[i]/2] for i in range(3)]
        lGridBoundPoints = array([[lGridBounds[i][0]*delGrids[i],lGridBounds[i][1]*delGrids[i]] for i in range(3)])
        lGridPoints = array([map(lambda x: x*delGrids[i],range(lGridCenter[i]-lGridSize[i]/2,lGridCenter[i]+lGridSize[i]/2)) for i in range(3)])

        #Stitch together field in local field (lfield) to enforce periodicity, use bounds to simplify
        bnds=list()
        lbnds=list()
        bnds.append(list(lGridBounds))
        lbnds.append(map(list,zip([0,0,0],lGridSize)))
        while outOfBounds(bnds,fieldSize):
            a=whichBounds(bnds,fieldSize)
            bnds.append(map(list,bnds[a]))
            lbnds.append(map(list,lbnds[a]))
            for i in range(3):
                if bnds[-1][i][1] > fieldSize[i]:
                    lbnds[a][i][1] = lGridSize[i]-(bnds[-1][i][1]-fieldSize[i])
                    lbnds[-1][i][0] = lGridSize[i]-(bnds[-1][i][1]-fieldSize[i])
                    lbnds[-1][i][1] = lbnds[-1][i][0]+(bnds[-1][i][1]-fieldSize[i])

                    bnds[-1][i][0]  = 0
                    bnds[-1][i][1] -= fieldSize[i]
                    bnds[a][i][1]   = fieldSize[i]
                    break

                elif bnds[-1][i][0] < 0:
                    lbnds[-1][i][0] = 0
                    lbnds[-1][i][1] = -bnds[-1][i][0]
                    lbnds[a][i][0] = -bnds[-1][i][0]

                    bnds[-1][i][1]  = fieldSize[i]
                    bnds[-1][i][0] += fieldSize[i]
                    bnds[a][i][0]   = 0
                    break

        lfield=zeros(lGridSize)
        for lbnd,bnd in zip(lbnds,bnds):
            [[lxa,lxb],[lya,lyb],[lza,lzb]]=lbnd
            [[xa,xb],[ya,yb],[za,zb]]=bnd
            lfield[lxa:lxb, lya:lyb, lza:lzb]=field[xa:xb, ya:yb, za:zb]

        #Loop over Neighboring atoms within the local grid
        for jNeighb in jNeighbors:
            xlines[-1].append(zeros([Ninterp]))
            ylines[-1].append(zeros([Ninterp]))
            atomj=latoms[jNeighb]
            for i,aj in enumerate(atomj):
                if aj < lGridPoints[i][0]:
                    atomj[i]+=simSize[i]
                if aj > lGridPoints[i][-1]:
                    atomj[i]-=simSize[i]

            #Error detection
            if  atomj[0]>lGridPoints[0][-1] or atomj[1]>lGridPoints[1][-1] or atomj[2]>lGridPoints[2][-1] or \
                atomj[0]<lGridPoints[0][0]  or atomj[1]<lGridPoints[1][0]  or atomj[2]<lGridPoints[2][0]:
                d=dist_periodic(atomi,atomj,array(zip([0,0,0],simSize)))
                if d>7.5: continue
                print "="*50
                print "Start Error Report:"
                print "AtomI(%d):"%iNeighb,atomi
                print "AtomJ(%d):"%jNeighb,atomj
                print "Distance:",dist_periodic(atomi,atomj,array(zip([0,0,0],simSize)))
                print "GridX Min,Max:","% 5.5f % 5.5f"%(min(lGridPoints[0]),max(lGridPoints[0]))
                print "GridY Min,Max:","% 5.5f % 5.5f"%(min(lGridPoints[1]),max(lGridPoints[1]))
                print "GridZ Min,Max:","% 5.5f % 5.5f"%(min(lGridPoints[2]),max(lGridPoints[2]))

                print "Error: AtomJ seems to be lying outside the local grid, which should not be possible."
                exit(0)
            
            #This is where the magic happens, finally do some computing...
            #Interpolate on local FIELD grid between these two atoms 75% of time spent here
            pnts2interp=linePoints(atomi,atomj,Ninterp) 
            yys=array([interp3d(i,lGridBoundPoints,lGridPoints,lfield) for i in pnts2interp])
            xwid=dist(pnts2interp[0],pnts2interp[-1])
            xdel=xwid/Ninterp
            xxs=[xdel*x-xwid/2 for x in range(Ninterp)]
            xlines[-1][-1]=xxs
            ylines[-1][-1]=yys
            avgyline+=yys

    avgyline/=nlines
    return avgyline,xlines,ylines,halfNeighbors