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 __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
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
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