Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
    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)
Ejemplo n.º 4
0
 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)
Ejemplo n.º 5
0
 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)
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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