示例#1
0
    def __init__(self,
                 calc,
                 charge_density='Gaussian',
                 solver=None,
                 accuracy_goal=12):
        self.calc = proxy(calc)
        self.norb = calc.el.get_nr_orbitals()
        self.SCC = calc.get('SCC')
        self.N = len(calc.el)
        self.dq = np.zeros((self.N))
        self.G = np.zeros((self.N, self.N))
        self.dG = np.zeros((self.N, self.N, 3))

        self.accuracy_goal = accuracy_goal

        if not charge_density in _gamma_correction_dict.keys():
            raise RuntimeError("Unknown charge density type: %s." %
                               charge_density)

        self.gamma_correction = _gamma_correction_dict[charge_density]

        if solver is None:
            cut = self.calc.get('gamma_cut')
            if self.SCC and cut == None and np.any(
                    self.calc.el.atoms.get_pbc()):
                raise AssertionError(
                    'gamma_cut must be provided for periodic calculations and with DirectCoulomb'
                )
            self.solver = DirectCoulomb(cut)
        else:
            self.solver = solver
示例#2
0
    def __init__(self, calc, charge_density='Gaussian',
                 solver=None, accuracy_goal=12):
        self.calc=proxy(calc)
        self.norb=calc.el.get_nr_orbitals()
        self.SCC=calc.get('SCC')
        self.N=len(calc.el)
        self.dq=np.zeros((self.N))
        self.G=np.zeros((self.N,self.N))
        self.dG=np.zeros((self.N,self.N,3))

        self.accuracy_goal = accuracy_goal

        if not charge_density in _gamma_correction_dict.keys():
            raise RuntimeError("Unknown charge density type: %s." %
                               charge_density)

        self.gamma_correction = _gamma_correction_dict[charge_density]

        if solver is None:
            cut = self.calc.get('gamma_cut')
            if self.SCC and cut==None and np.any(self.calc.el.atoms.get_pbc()):
                raise AssertionError('gamma_cut must be provided for periodic calculations and with DirectCoulomb')
            self.solver = DirectCoulomb(cut)
        else:
            self.solver = solver
示例#3
0
class Electrostatics:
    def __init__(self, calc, charge_density='Gaussian',
                 solver=None, accuracy_goal=12):
        self.calc=proxy(calc)
        self.norb=calc.el.get_nr_orbitals()
        self.SCC=calc.get('SCC')
        self.N=len(calc.el)
        self.dq=np.zeros((self.N))
        self.G=np.zeros((self.N,self.N))
        self.dG=np.zeros((self.N,self.N,3))

        self.accuracy_goal = accuracy_goal

        if not charge_density in _gamma_correction_dict.keys():
            raise RuntimeError("Unknown charge density type: %s." %
                               charge_density)

        self.gamma_correction = _gamma_correction_dict[charge_density]

        if solver is None:
            cut = self.calc.get('gamma_cut')
            if self.SCC and cut==None and np.any(self.calc.el.atoms.get_pbc()):
                raise AssertionError('gamma_cut must be provided for periodic calculations and with DirectCoulomb')
            self.solver = DirectCoulomb(cut)
        else:
            self.solver = solver


    def set_dq(self,dq):
        """ (Re)setting dq gives new gamma-potential. """
        self.dq=dq
        self.epsilon = np.sum(self.G*self.dq, axis=1)
        if self.solver is not None:
            self.solver.update(self.calc.el.atoms, dq)
            # Unit mess: The Coulomb solver is unit agnostic, but the Elements
            # object returns the distances in Bohr (from get_distances())
            self.epsilon += self.solver.get_potential()*Bohr


    def coulomb_energy(self):
        """ Return Coulomb energy. """
        self.calc.start_timing('ecoul')
        ecoul = 0.0
        if not self.SCC:
            ecoul = 0.0
        else:
            ecoul = 0.5 * dot(self.dq,self.epsilon)
        self.calc.stop_timing('ecoul')
        return ecoul


    def gamma_forces(self):
        """ Return forces due to electrostatic interactions. """
        if not self.SCC:
            return np.zeros((self.N,3))
        else:
            self.calc.start_timing('f_es')
            if self.solver is None:
                E = np.zeros((self.N,3))
            else:
                # Unit mess: The Coulomb solver is unit agnostic, but the
                # Elements object returns the distances in Bohr
                # (from get_distances())
                E = self.solver.get_field()*Bohr**2
            depsilon  = np.sum(self.dq.reshape(1, -1, 1)*self.dG, axis=1)
            f         = self.dq.reshape(-1, 1) * ( depsilon + E )
            self.calc.stop_timing('f_es')
            return f


    def construct_h1(self,dq=None):
        """ Make the electrostatic part of the Hamiltonian. """
        self.calc.start_timing('h1')
        if dq!=None:
            self.set_dq(dq)
                          
        lst = self.calc.el.get_property_lists(['i','o1','no'])
        
        aux = np.zeros((self.norb,self.norb))
        for i,o1i,noi in lst:
            aux[o1i:o1i+noi,:] = self.epsilon[i]
        h1 = 0.5 * ( aux+aux.transpose() )
                
        # external electrostatics
        if np.any(abs(self.ext)>1E-12):
            aux = np.zeros((self.norb,self.norb))
            for i,o1i,noi in lst:
                aux[o1i:o1i+noi,:] = self.ext[i]
            h1 = h1 + 0.5 * (-1) * (aux+aux.transpose())
                
        self.calc.stop_timing('h1')
        self.h1=h1
        return self.h1


    def get_h1(self):
        """ Get the current electrostatic Hamiltonian. """
        return self.h1


    def construct_Gamma_matrix(self, a):
        '''
        Construct the G-matrix and its derivative.
        
        Done once for each geometry; 
        G_ij = sum_n gamma_ij(Rijn)
        dG_ij = sum_n gamma'_ij(Rijn) hat(Rijn) 
        '''
        self.calc.start_timing('gamma matrix')

        U = [ self.calc.el.get_element(i).get_U()
              for i in range(len(a)) ]
        FWHM = [ self.calc.el.get_element(i).get_FWHM()
                 for i in range(len(a)) ]

        G, dG = self.gamma_correction(a, U,
                                      FWHM = FWHM,
                                      cutoff = self.calc.get('gamma_cut'),
                                      accuracy_goal = self.accuracy_goal)

        self.G, self.dG  = G, dG

        self.ext = np.array( [self.calc.env.phi(i) for i in range(self.N)] )
        self.calc.stop_timing('gamma matrix')


    def get_gamma(self):
        return self.G + self.solver.get_gamma()*Bohr


### For use as a standalone calculator, return eV/A units

    def get_potential_energy(self, a):
        self.calc.el.update_geometry(a)
        self.construct_Gamma_matrix(a)
        self.set_dq(a.get_charges())
        return self.coulomb_energy()*Hartree

    def get_forces(self, a):
        self.calc.el.update_geometry(a)
        self.construct_Gamma_matrix(a)
        self.set_dq(a.get_charges())
        return self.gamma_forces()*Hartree/Bohr
示例#4
0
class Electrostatics:
    def __init__(self,
                 calc,
                 charge_density='Gaussian',
                 solver=None,
                 accuracy_goal=12):
        self.calc = proxy(calc)
        self.norb = calc.el.get_nr_orbitals()
        self.SCC = calc.get('SCC')
        self.N = len(calc.el)
        self.dq = np.zeros((self.N))
        self.G = np.zeros((self.N, self.N))
        self.dG = np.zeros((self.N, self.N, 3))

        self.accuracy_goal = accuracy_goal

        if not charge_density in _gamma_correction_dict.keys():
            raise RuntimeError("Unknown charge density type: %s." %
                               charge_density)

        self.gamma_correction = _gamma_correction_dict[charge_density]

        if solver is None:
            cut = self.calc.get('gamma_cut')
            if self.SCC and cut == None and np.any(
                    self.calc.el.atoms.get_pbc()):
                raise AssertionError(
                    'gamma_cut must be provided for periodic calculations and with DirectCoulomb'
                )
            self.solver = DirectCoulomb(cut)
        else:
            self.solver = solver

    def set_dq(self, dq):
        """ (Re)setting dq gives new gamma-potential. """
        self.dq = dq
        self.epsilon = np.sum(self.G * self.dq, axis=1)
        if self.solver is not None:
            self.solver.update(self.calc.el.atoms, dq)
            # Unit mess: The Coulomb solver is unit agnostic, but the Elements
            # object returns the distances in Bohr (from get_distances())
            self.epsilon += self.solver.get_potential() * Bohr

    def coulomb_energy(self):
        """ Return Coulomb energy. """
        self.calc.start_timing('ecoul')
        ecoul = 0.0
        if not self.SCC:
            ecoul = 0.0
        else:
            ecoul = 0.5 * dot(self.dq, self.epsilon)
        self.calc.stop_timing('ecoul')
        return ecoul

    def gamma_forces(self):
        """ Return forces due to electrostatic interactions. """
        if not self.SCC:
            return np.zeros((self.N, 3))
        else:
            self.calc.start_timing('f_es')
            if self.solver is None:
                E = np.zeros((self.N, 3))
            else:
                # Unit mess: The Coulomb solver is unit agnostic, but the
                # Elements object returns the distances in Bohr
                # (from get_distances())
                E = self.solver.get_field() * Bohr**2
            depsilon = np.sum(self.dq.reshape(1, -1, 1) * self.dG, axis=1)
            f = self.dq.reshape(-1, 1) * (depsilon + E)
            self.calc.stop_timing('f_es')
            return f

    def construct_h1(self, dq=None):
        """ Make the electrostatic part of the Hamiltonian. """
        self.calc.start_timing('h1')
        if dq != None:
            self.set_dq(dq)

        lst = self.calc.el.get_property_lists(['i', 'o1', 'no'])

        aux = np.zeros((self.norb, self.norb))
        for i, o1i, noi in lst:
            aux[o1i:o1i + noi, :] = self.epsilon[i]
        h1 = 0.5 * (aux + aux.transpose())

        # external electrostatics
        if np.any(abs(self.ext) > 1E-12):
            aux = np.zeros((self.norb, self.norb))
            for i, o1i, noi in lst:
                aux[o1i:o1i + noi, :] = self.ext[i]
            h1 = h1 + 0.5 * (-1) * (aux + aux.transpose())

        self.calc.stop_timing('h1')
        self.h1 = h1
        return self.h1

    def get_h1(self):
        """ Get the current electrostatic Hamiltonian. """
        return self.h1

    def construct_Gamma_matrix(self, a):
        '''
        Construct the G-matrix and its derivative.
        
        Done once for each geometry; 
        G_ij = sum_n gamma_ij(Rijn)
        dG_ij = sum_n gamma'_ij(Rijn) hat(Rijn) 
        '''
        self.calc.start_timing('gamma matrix')

        U = [self.calc.el.get_element(i).get_U() for i in range(len(a))]
        FWHM = [self.calc.el.get_element(i).get_FWHM() for i in range(len(a))]

        G, dG = self.gamma_correction(a,
                                      U,
                                      FWHM=FWHM,
                                      cutoff=self.calc.get('gamma_cut'),
                                      accuracy_goal=self.accuracy_goal)

        self.G, self.dG = G, dG

        self.ext = np.array([self.calc.env.phi(i) for i in range(self.N)])
        self.calc.stop_timing('gamma matrix')

    def get_gamma(self):
        return self.G + self.solver.get_gamma() * Bohr

### For use as a standalone calculator, return eV/A units

    def get_potential_energy(self, a):
        self.calc.el.update_geometry(a)
        self.construct_Gamma_matrix(a)
        self.set_dq(a.get_charges())
        return self.coulomb_energy() * Hartree

    def get_forces(self, a):
        self.calc.el.update_geometry(a)
        self.construct_Gamma_matrix(a)
        self.set_dq(a.get_charges())
        return self.gamma_forces() * Hartree / Bohr