Пример #1
0
 def __init__(self,distr=None,xgrid=None):
     """ 
     Initialize either with given probability distribution 'distr(x)',
     or give the distribution on grid (given grid or 0,1,2,... by default)
     """
     try:
         distr(0.0)
         self.f=distr
     except:
         self.x=xgrid
         if self.x is None:
             self.x=range(len(distr))
         self.distr=distr
         self.f=SplineFunction(self.x,self.distr,k=1)
             
     # put the probability distribution f(x) on grid
     self.N=1000
     self.lim=self.f.limits()
     self.xgrid=np.linspace(self.lim[0],self.lim[1],self.N)
     self.fvals=[self.f(z) for z in self.xgrid]
     
     # construct the distribution function F(x)
     cum=[0.0]
     for i in range(self.N-1):
         cum.append(cum[-1]+self.fvals[i]+self.fvals[i+1])
     cum=np.array(cum)/2*(self.lim[1]-self.lim[0])/self.N
     self.norm=cum[-1]
     cum=cum/self.norm
     self.F=SplineFunction(self.xgrid,cum,k=1)
Пример #2
0
    def __init__(self, distr=None, xgrid=None):
        """ 
        Initialize either with given probability distribution 'distr(x)',
        or give the distribution on grid (given grid or 0,1,2,... by default)
        """
        try:
            distr(0.0)
            self.f = distr
        except:
            self.x = xgrid
            if self.x is None:
                self.x = range(len(distr))
            self.distr = distr
            self.f = SplineFunction(self.x, self.distr, k=1)

        # put the probability distribution f(x) on grid
        self.N = 1000
        self.lim = self.f.limits()
        self.xgrid = np.linspace(self.lim[0], self.lim[1], self.N)
        self.fvals = [self.f(z) for z in self.xgrid]

        # construct the distribution function F(x)
        cum = [0.0]
        for i in range(self.N - 1):
            cum.append(cum[-1] + self.fvals[i] + self.fvals[i + 1])
        cum = np.array(cum) / 2 * (self.lim[1] - self.lim[0]) / self.N
        self.norm = cum[-1]
        cum = cum / self.norm
        self.F = SplineFunction(self.xgrid, cum, k=1)
Пример #3
0
    def append_energy_slope(self,
                            weight,
                            p,
                            dEdp,
                            p0,
                            calc,
                            traj,
                            comment=None,
                            label=None,
                            color=None):
        """
        Calculates the V'rep(r) at one point using trajectory over parameters p.

        Trajectory is calculated using parameters p, giving E(p), where E is the total energy
        without Vrep(r). The pair distance R=R(p). At p=p0, we set dE/dp|p=p0=dEdp, from which
        we can set V'rep(R(p)) as

                    dEdp - dE/dp(p0)
        V'rep(r) = -------------------
                      N * dR/dp

        parameters:
        ===========
        weight:              fitting weight
        p:                   parameter list
        dEdp:                slope of energy at p0
        p0:                  the point where energy slope is set
        calc:                Hotbit calculator (remember charge and k-points)
        traj:                filename for ASE trajectory, or PickleTrajectory
                             object
        comment:             fitting comment for par-file (replaced by comment if None)
        label:               plotting label (replaced by comment if None)
        color:               plotting color
        """
        raise NotImplementedError('This method was never tested properly.')
        from box.interpolation import SplineFunction
        R, E, N = [], [], []
        for atoms in traj:
            a, c = self._set_calc(atoms, calc)
            e = a.get_potential_energy()
            r, n = self._get_repulsion_distances(c)
            if n > 0 and r < self.r_cut:
                E.append(atoms.get_potential_energy())
                R.append(r)
                N.append(n)

        R, E, N = np.array(R), np.array(E), np.array(N)
        if np.any(N[0] != N):
            raise NotImplementedError(
                'The number of bonds changes during trajectory; check implementation.'
            )

        Ef = SplineFunction(p, E)
        Rf = SplineFunction(p, R)

        color = self._get_color(color)
        comment += ';w=%.1f;N=%i' % (weight, N[0])
        return self.append_point(weight, Rf(p0), (dEdp - Ef(p0, der=1)) /
                                 (N[0] * Rf(p0, der=1)), comment, label, color)
Пример #4
0
class ArbitraryDistribution:
    """ Class for generating random numbers form given distribution. """
    
    def __init__(self,distr=None,xgrid=None):
        """ 
        Initialize either with given probability distribution 'distr(x)',
        or give the distribution on grid (given grid or 0,1,2,... by default)
        """
        try:
            distr(0.0)
            self.f=distr
        except:
            self.x=xgrid
            if self.x is None:
                self.x=range(len(distr))
            self.distr=distr
            self.f=SplineFunction(self.x,self.distr,k=1)
                
        # put the probability distribution f(x) on grid
        self.N=1000
        self.lim=self.f.limits()
        self.xgrid=np.linspace(self.lim[0],self.lim[1],self.N)
        self.fvals=[self.f(z) for z in self.xgrid]
        
        # construct the distribution function F(x)
        cum=[0.0]
        for i in range(self.N-1):
            cum.append(cum[-1]+self.fvals[i]+self.fvals[i+1])
        cum=np.array(cum)/2*(self.lim[1]-self.lim[0])/self.N
        self.norm=cum[-1]
        cum=cum/self.norm
        self.F=SplineFunction(self.xgrid,cum,k=1)
        
    def __call__(self):
        """ Generate random number from given distribution. """
        rnd=np.random.uniform(0.0,1.0)
        return self.F.solve(rnd)
    
    def verify(self,nr=10000):
        """ Plot and compare given distribution and simulated one. """
        c=np.array([self() for rnd in range(nr)])
        
        import pylab as pl
        pl.hist(c,len(self.xgrid),normed=True)
        distr=[self.f(x)/self.norm for x in self.xgrid]
        pl.plot(self.xgrid,distr,c='r')
        pl.show()
Пример #5
0
    def run(self):
        """
        Solve the self-consistent potential.
        """
        self.timer.start('solve ground state')
        print('\nStart iteration...', file=self.txt)
        self.enl={}
        self.d_enl={}
        for n,l,nl in self.list_states():
            self.enl[nl]=0.0
            self.d_enl[nl]=0.0

        N=self.grid.get_N()

        # make confinement and nuclear potentials; intitial guess for veff
        self.conf=array([self.confinement_potential(r) for r in self.rgrid])
        self.nucl=array([self.V_nuclear(r) for r in self.rgrid])
        self.get_veff_and_dens()
        self.calculate_Hartree_potential()
        #self.Hartree=np.zeros((N,))

        for it in range(self.itmax):
            self.veff=self.mix*self.calculate_veff()+(1-self.mix)*self.veff
            if self.scalarrel:
                veff = SplineFunction(self.rgrid, self.veff)
                self.dveff = array([veff(r, der=1) for r in self.rgrid])
            d_enl_max, itmax=self.solve_eigenstates(it)

            dens0=self.dens.copy()
            self.dens=self.calculate_density()
            diff=self.grid.integrate(np.abs(self.dens-dens0),use_dV=True)

            if diff<self.convergence['density'] and d_enl_max<self.convergence['energies'] and it > 5:
                break
            self.calculate_Hartree_potential()
            if np.mod(it,10)==0:
                print('iter %3i, dn=%.1e>%.1e, max %i sp-iter' %(it,diff,self.convergence['density'],itmax), file=self.txt)
            if it==self.itmax-1:
                if self.timing:
                    self.timer.summary()
                raise RuntimeError('Density not converged in %i iterations' %(it+1))
            self.txt.flush()

        self.calculate_energies(echo=True)
        print('converged in %i iterations' %it, file=self.txt)
        print('%9.4f electrons, should be %9.4f' %(self.grid.integrate(self.dens,use_dV=True),self.nel), file=self.txt)
        for n,l,nl in self.list_states():
            self.Rnl_fct[nl]=Function('spline',self.rgrid,self.Rnlg[nl])
            self.unl_fct[nl]=Function('spline',self.rgrid,self.unlg[nl])
        self.timer.stop('solve ground state')
        self.timer.summary()
        self.txt.flush()
        self.solved=True
        if self.write != None:
            f=open(self.write,'wb')
            pickle.dump(self.rgrid, f)
            pickle.dump(self.veff, f)
            pickle.dump(self.dens, f)
            f.close()
Пример #6
0
class ArbitraryDistribution:
    """ Class for generating random numbers form given distribution. """
    def __init__(self, distr=None, xgrid=None):
        """ 
        Initialize either with given probability distribution 'distr(x)',
        or give the distribution on grid (given grid or 0,1,2,... by default)
        """
        try:
            distr(0.0)
            self.f = distr
        except:
            self.x = xgrid
            if self.x is None:
                self.x = range(len(distr))
            self.distr = distr
            self.f = SplineFunction(self.x, self.distr, k=1)

        # put the probability distribution f(x) on grid
        self.N = 1000
        self.lim = self.f.limits()
        self.xgrid = np.linspace(self.lim[0], self.lim[1], self.N)
        self.fvals = [self.f(z) for z in self.xgrid]

        # construct the distribution function F(x)
        cum = [0.0]
        for i in range(self.N - 1):
            cum.append(cum[-1] + self.fvals[i] + self.fvals[i + 1])
        cum = np.array(cum) / 2 * (self.lim[1] - self.lim[0]) / self.N
        self.norm = cum[-1]
        cum = cum / self.norm
        self.F = SplineFunction(self.xgrid, cum, k=1)

    def __call__(self):
        """ Generate random number from given distribution. """
        rnd = np.random.uniform(0.0, 1.0)
        return self.F.solve(rnd)

    def verify(self, nr=10000):
        """ Plot and compare given distribution and simulated one. """
        c = np.array([self() for rnd in range(nr)])

        import pylab as pl
        pl.hist(c, len(self.xgrid), normed=True)
        distr = [self.f(x) / self.norm for x in self.xgrid]
        pl.plot(self.xgrid, distr, c='r')
        pl.show()
Пример #7
0
 def derivative(self, f, order=1):
     """
     Get order-th derivative of function f (given with N grid points).
     """
     x = self.get_grid()
     f_spline = SplineFunction(x, f)
     dfdx = f_spline(x, der=order)
     return dfdx
Пример #8
0
 def _integrate_vrep(self, dv_rep, r_cut, N=100):
     """
     Integrate V'_rep(r) from r_cut to zero to get the V_rep(r)
     """
     from box.interpolation import SplineFunction
     from scipy.integrate import quadrature
     r_g = np.linspace(r_cut, 0, N)
     dr = r_g[1] - r_g[0]
     v_rep = np.zeros(N)
     for i in range(1,len(r_g)):
         v_rep[i] = v_rep[i-1]
         val, err = quadrature(dv_rep, r_g[i-1], r_g[i], tol=1.0e-12, maxiter=50)
         v_rep[i] += val
     # SplineFunction wants the x-values in ascending order
     return SplineFunction(r_g[::-1], v_rep[::-1])
Пример #9
0
def vrep_to_spline_coefficients(rep):
    """ 
        Transform simple grid data to spline form used by DFTB+
    Input:
    rep:    rep[:,0]=r and rep[:,1]=v(r)
    
    Output:
    spline: List with spline data
            Each line with: start end c0 c1 c2 c3
            where v is interpolated between [start,end] using
            v(r) = c0 + c1*(r-start)+ c2*(r-start)**2 + c3*(r-start)**3
            The last line has coefficients up to c5.
    """
    print(rep.shape)
    v = SplineFunction(rep[:, 0], rep[:, 1])
    n = rep.shape[0]
    m = 6
    spline = []
    for i in range(n - 1):
        r0, r1 = rep[i, 0], rep[i + 1, 0]
        v0, v1 = rep[i, 1], rep[i + 1, 1]
        rlist = linspace(r0, r1, m)
        vlist = v(rlist)
        if i == n - 2:
            nc = 1 + 5
        else:
            nc = 1 + 3
        pguess = zeros(nc)
        pguess[0] = 0.5 * (v0 + v1)
        pguess[1] = (v1 - v0) / (r1 - r0)

        def chi2(p, x, y):
            err = y - vrep_poly(x, r0, p)
            return sum(err**2)

        p = fmin(chi2, pguess, args=(rlist, vlist), xtol=1E-12, disp=False)
        spline.append([r0, r1] + list(p))
    return spline
Пример #10
0
    def append_energy_curve(self,weight,calc,traj,comment=None,label=None,color=None):
        """
        Calculates the V'rep(r) from a given ase-trajectory.

        The trajectory can be anything, as long as the ONLY missing energy
        from DFTB calculation is N*V_rep(R). Hence

            E_DFT(R) = E_wr(R) + N*V_rep(R)

                         E_DFT'(R) - E_wr'(R)
            V_rep'(R) =  ------------------ ,
                                N

        where R is the nn. distance,N is the number of A-B pairs taken into account,
        and E_wr(R) = E_bs(R) + E_coul(R) is the DFTB energy without repulsion.
        At least 3 points in energy curve needed, preferably more.

        parameters:
        ===========
        weight:              fitting weight
        calc:                Hotbit calculator (remember charge and k-points)
        traj:                filename for ASE trajectory, or PickleTrajectory
                             object
        comment:             fitting comment for par-file (replaced by comment if None)
        label:               plotting label (replaced by comment if None)
        color:               plotting color
        """
        if comment==None: comment=label
        if label==None: label=comment

        #if not ( isinstance(traj, type(PickleTrajectory)) or isinstance(traj, list) ):
        if not ( isinstance(traj, type(PickleTrajectory)) or isinstance(traj, list) ):
            print("\nAppending energy curve data from %s..." %traj, file=self.txt)
            traj = PickleTrajectory(traj)
        else:
            print('\nAppending energy curve data...', file=self.txt)
        Edft, Ewr, N, R = [], [], [], []
        if len(traj)<3:
            raise AssertionError('At least 3 points in energy curve required.')
        for atoms in traj:
            a, c = self._set_calc(atoms,calc)
            e = a.get_potential_energy()
            r, n = self._get_repulsion_distances(c)
            if n>0 and r<self.r_cut:
                Edft.append( atoms.get_potential_energy() )
                Ewr.append( e )
                R.append(r)
                N.append(n)
        Edft = np.array(Edft)
        Ewr = np.array(Ewr)
        N = np.array(N)
        R = np.array(R)

        if np.any( N-N[0]!=0 ):
            raise RuntimeError('The number of bonds changes within trajectory.')

        # sort radii because of spline
        ind = R.argsort()
        R    = R[ind]
        Edft = Edft[ind]
        Ewr  = Ewr[ind]
        from box.interpolation import SplineFunction
        k = min(len(Edft)-2,3)
        vrep = SplineFunction(R, (Edft-Ewr)/N, k=k, s=0)

        color = self._get_color(color)
        for i, r in enumerate(R):
            if i==0:
                com = comment + ';w=%.1f' %weight
            else:
                label='_nolegend_'
                com = None
            self.append_point(weight/np.sqrt(len(R)),r, vrep(r,der=1), com, label, color)
        print("Appended %i points around R=%.4f...%.4f" %(len(N),R.min(),R.max()), file=self.txt)
Пример #11
0
def write_skf(el1, el2, data1, data2, tables, rep, spline, dr=0.1):
    """ Write .skf files for el1-el2 interactions. 
    Input:
    el1:    element 1 symbol
    el2:    element 2 symbol 
    data1:  dictionary for element 1 data
    data2:  dictionary for element 2 data
    tables: dictionary for Slater-Koster table data
    rep:    repulsive potential on a grid
    spline: spline in appropriate format already
    dr:     output grid spacing
    """
    if el1 == el2:
        filename = '%s-%s.skf' % (el1, el2)
        o = open(filename, 'w')
        ng = int(ceil(tables['grid'][-1] / dr))
        o.write('%.15f, %i, ' % (dr, ng))
        e = data1['energies']
        u = data1['U']
        occ = data1['occupations']
        occ = [2, 2]
        # Ed Ep Es SPE Ud Up Us fd fp fs (orbital energies and Hubbard U)
        o.write("{} {} {} {} {} {} {} {} {} {} \n".format(
            0.0, e[0], e[1], 0., u, u, u, 0.0, occ[0], occ[1]))
        # mass c2 c3 c4 c5 c6 c7 c8 c9 rcut d1 d2 d3 d4 d5 d6 d7 d8 d9 d10
        # where c* are vrep coefficients (unless spline) and d* are not used
        o.write("{} {} {} {} {} {} {} {} {} {} \n".format(
            data1['mass'] * 2, 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
            0., 0., 0., 0., 0., 0., 0.))
        #
        # interpolate SlaKo tables
        #
        tab = tables['%s%s' % (el1, el2)]  #[i,j]
        f = [SplineFunction(tables['grid'], tab[:, i]) for i in range(20)]
        for i in range(ng):
            for j in range(20):
                o.write("{} ".format(f[j]((i + 1) * dr)))
            o.write("\n")
            #print>>o
        #
        # repulsion
        #
        o.write('Spline \n')
        o.write("{} {} \n".format(len(spline), spline[-1][1]))  #nInt, cutoff
        o.write(" {} {} {} \n".format(0, -1E19, spline[0][2]))
        for sp in spline:
            #print(' '.join([str(x) for x in sp]))
            o.write(' '.join([str(x) for x in sp]))
            o.write("\n")

        #print>>o
        o.close()

    else:
        for e1, e2 in [(el1, el2), (el2, el1)]:
            filename = '%s-%s.skf' % (e1, e2)
            o = open(filename, 'w')
            ng = int(ceil(tables['grid'][-1] / dr))
            o.write('%.15f, %i, ' % (dr, ng))
            o.write(0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,
                    0., 0., 0., 0., 0.)

            #
            # interpolate SlaKo tables
            #
            tab = tables['%s%s' % (e1, e2)]  #[i,j]
            f = [SplineFunction(tables['grid'], tab[:, i]) for i in range(20)]
            for i in range(ng):
                for j in range(20):
                    o.write(f[j]((i + 1) * dr), '\n')
                #print>>o
            #
            # repulsion
            #
            o.write('Spline')
            o.write(len(spline), spline[-1][1])  #nInt, cutoff
            o.write(0, -1E19, spline[0][2])
            for sp in spline:
                o.write(' '.join([str(x) for x in sp], '\n'))
            #print>>o
            o.close()