def solve_poisson_becke(density_decomposition): '''Compute the electrostatic potential of a density expanded in real spherical harmonics **Arguments:** density_decomposition A list of cubic splines returned by the method AtomicGrid.get_spherical_decomposition. The returned list of splines is a spherical decomposition of the hartree potential (felt by a particle with the same charge unit as the density). ''' biblio.cite('becke1988_poisson', 'the numerical integration of the Poisson equation') lmax = np.sqrt(len(density_decomposition)) - 1 assert lmax == int(lmax) lmax = int(lmax) result = [] counter = 0 for l in xrange(0, lmax + 1): for m in xrange(-l, l + 1): rho = density_decomposition[counter] rtf = rho.rtransform rgrid = RadialGrid(rtf) radii = rtf.get_radii() # The approach followed here is obtained after substitution of # u = r*V in Eq. (21) in Becke's paper. After this transformation, # the boundary conditions can be implemented such that the output # is more accurate. fy = -4 * np.pi * rho.y fd = -4 * np.pi * rho.dx f = CubicSpline(fy, fd, rtf) b = CubicSpline(2 / radii, -2 / radii**2, rtf) a = CubicSpline(-l * (l + 1) * radii**-2, 2 * l * (l + 1) * radii**-3, rtf) # Derivation of boundary condition at rmax: # Multiply differential equation with r**l and integrate. Using # partial integration and the fact that V(r)=A/r**(l+1) for large # r, we find -(2l+1)A=-4pi*int_0^infty r**2 r**l rho(r) and so # V(rmax) = A/rmax**(l+1) = integrate(r**l rho(r))/(2l+1)/rmax**(l+1) V_rmax = rgrid.integrate( rho.y * radii**l) / radii[-1]**(l + 1) / (2 * l + 1) # Derivation of boundary condition at rmin: # Same as for rmax, but multiply differential equation with r**(-l-1) # and assume that V(r)=B*r**l for small r. V_rmin = rgrid.integrate( rho.y * radii**(-l - 1)) * radii[0]**(l) / (2 * l + 1) bcs = (V_rmin, None, V_rmax, None) v = solve_ode2(b, a, f, bcs, PotentialExtrapolation(l)) result.append(v) counter += 1 return result
def solve_poisson_becke(density_decomposition): '''Compute the electrostatic potential of a density expanded in real spherical harmonics **Arguments:** density_decomposition A list of cubic splines returned by the method AtomicGrid.get_spherical_decomposition. The returned list of splines is a spherical decomposition of the hartree potential (felt by a particle with the same charge unit as the density). ''' log.cite('becke1988_poisson', 'the numerical integration of the Poisson equation') lmax = np.sqrt(len(density_decomposition)) - 1 assert lmax == int(lmax) lmax = int(lmax) result = [] counter = 0 for l in xrange(0, lmax+1): for m in xrange(-l, l+1): rho = density_decomposition[counter] rtf = rho.rtransform rgrid = RadialGrid(rtf) radii = rtf.get_radii() # The approach followed here is obtained after substitution of # u = r*V in Eq. (21) in Becke's paper. After this transformation, # the boundary conditions can be implemented such that the output # is more accurate. fy = -4*np.pi*rho.y fd = -4*np.pi*rho.dx f = CubicSpline(fy, fd, rtf) b = CubicSpline(2/radii, -2/radii**2, rtf) a = CubicSpline(-l*(l+1)*radii**-2, 2*l*(l+1)*radii**-3, rtf) # Derivation of boundary condition at rmax: # Multiply differential equation with r**l and integrate. Using # partial integration and the fact that V(r)=A/r**(l+1) for large # r, we find -(2l+1)A=-4pi*int_0^infty r**2 r**l rho(r) and so # V(rmax) = A/rmax**(l+1) = integrate(r**l rho(r))/(2l+1)/rmax**(l+1) V_rmax = rgrid.integrate(rho.y*radii**l)/radii[-1]**(l+1)/(2*l+1) # Derivation of boundary condition at rmin: # Same as for rmax, but multiply differential equation with r**(-l-1) # and assume that V(r)=B*r**l for small r. V_rmin = rgrid.integrate(rho.y*radii**(-l-1))*radii[0]**(l)/(2*l+1) bcs = (V_rmin, None, V_rmax, None) v = solve_ode2(b, a, f, bcs, PotentialExtrapolation(l)) result.append(v) counter += 1 return result
def _load(self, filename): fn = context.get_fn(filename) members = [] with open(fn) as f: state = 0 for line in f: line = line[:line.find('#')].strip() if len(line) > 0: if state == 0: # read element number words = line.split() number = int(words[0]) if len(words) > 1: pseudo_number = int(words[1]) else: pseudo_number = number state = 1 elif state == 1: # read rtf string rtf = RTransform.from_string(line) state = 2 elif state == 2: nlls = np.array([int(w) for w in line.split()]) state = 0 members.append( (number, pseudo_number, RadialGrid(rtf), nlls)) self._init_members_from_list(members)
def from_hdf5(cls, grp, lf): records = [] for ds in grp.itervalues(): rtransform = RTransform.from_string(ds.attrs['rtransform']) records.append((ds.attrs['number'], ds.attrs['pseudo_number'], RadialGrid(rtransform), ds[:])) return AtomicGridSpec(records)
def _init_members_from_string(self, definition): if os.path.isfile(definition): self._load(definition) return filename = context.get_fn('grids/%s.txt' % definition) if os.path.isfile(filename): self._load(filename) return name = self._simple_names.get(definition) if name is not None: filename = context.get_fn('grids/%s.txt' % name) self._load(filename) return if definition.count(':') == 4: words = self.name.split(':') RTransformClass = self._simple_rtfs.get(words[0]) if RTransformClass is None: raise ValueError('Unknown radial grid type: %s' % words[0]) rmin = float(words[1]) * angstrom rmax = float(words[2]) * angstrom nrad = int(words[3]) rgrid = RadialGrid(RTransformClass(rmin, rmax, nrad)) nll = int(words[4]) self._init_members_from_tuple((rgrid, nll)) else: raise ValueError( 'Could not interpret atomic grid specification string: "%s"' % definition)
def load_proatom_records_h5_group(f): '''Load proatom records from the given HDF5 group''' records = [] for grp in f.itervalues(): assert isinstance(grp, h5.Group) if 'deriv' in grp: deriv = grp['deriv'][:] else: deriv = None records.append(ProAtomRecord( number=grp.attrs['number'], charge=grp.attrs['charge'], energy=grp.attrs['energy'], rgrid=RadialGrid(RTransform.from_string(grp.attrs['rtransform'])), rho=grp['rho'][:], deriv=deriv, pseudo_number=grp.attrs.get('pseudo_number'), ipot_energy=grp.attrs.get('ipot_energy'), )) return records
def load_proatom_records_atdens(filename): '''Load proatom records from the given atdens file file''' def read_numbers(f, npoint): numbers = [] while len(numbers) < npoint: words = f.next().replace('D', 'E').split() for word in words: numbers.append(float(word)) return np.array(numbers) from horton.grid.cext import ExpRTransform records = [] with open(filename) as f: # load the radii words = f.next().split() assert words[0] == 'RADII' npoint = int(words[1]) radii = read_numbers(f, npoint) # Construct a radial grid r1 = radii[1] r2 = radii[-1] rtf = ExpRTransform(r1, r2, npoint-1) rgrid = RadialGrid(rtf) # load the proatoms while True: try: words = f.next().split() number = int(words[0]) population = int(words[1]) charge = number - population rho = read_numbers(f, npoint)[1:] record = ProAtomRecord(number, charge, 0.0, 0.0, rgrid, rho) records.append(record) except StopIteration: break return records