Beispiel #1
0
    def __init__(self, p1, p2, size, extend=0):
        """
           **Arguments:**

           p1, p2
                Two points defining the line segment

           size
                The number of grid points

           **Optional arguments:**

           extend
                Used to control how far the grid points extrapolate from the
                line segment.
        """
        self._p1 = p1
        self._p2 = p2
        norm = np.linalg.norm(p2 - p1)
        self._x = norm * (np.arange(size, dtype=float) / (size - 1) - 0.5)
        self._x *= 1 + 2 * extend
        points = np.outer(self._x, (p2 - p1) / norm) + 0.5 * (p2 + p1)
        assert points.shape == (size, 3)
        weight = norm / (size - 1)
        weights = np.empty(size)
        weights.fill(weight)
        IntGrid.__init__(self, points, weights)
Beispiel #2
0
def test_grid_integrate_segments():
    npoint = 10
    segments = np.array([2, 5, 3])
    grid = IntGrid(np.random.normal(0, 1, (npoint, 3)), np.random.normal(0, 1, npoint))
    pot = np.random.normal(0, 1, npoint)
    dens = np.random.normal(0, 1, npoint)

    # three
    ints = grid.integrate(pot, dens, segments=segments)
    assert ints.shape == (3,)
    product = grid.weights * pot * dens
    assert abs(ints[0] - product[:2].sum()) < 1e-10
    assert abs(ints[1] - product[2:7].sum()) < 1e-10
    assert abs(ints[2] - product[7:].sum()) < 1e-10

    # two
    ints = grid.integrate(pot, segments=segments)
    assert ints.shape == (3,)
    product = grid.weights * pot
    assert abs(ints[0] - product[:2].sum()) < 1e-10
    assert abs(ints[1] - product[2:7].sum()) < 1e-10
    assert abs(ints[2] - product[7:].sum()) < 1e-10

    # one
    ints = grid.integrate(segments=segments)
    assert ints.shape == (3,)
    assert abs(ints[0] - grid.weights[:2].sum()) < 1e-10
    assert abs(ints[1] - grid.weights[2:7].sum()) < 1e-10
    assert abs(ints[2] - grid.weights[7:].sum()) < 1e-10
Beispiel #3
0
    def __init__(self, origin, axis0, axis1, l0, h0, l1, h1):
        """
           **Arguments:**

           origin
                The origin for the definition of the rectangle.

           axis0, axis1
                The basis vectors that define the plane of the rectangle and
                the 2D space in this plane.

           l0, h0
                The lowest and highest position along axis0. (These must be
                integers.) Hence, along the first axis, there are (h0-l0+1)
                grid points.

           l1, h1
                The lowest and highest position along axis1.
        """
        if h0 <= l0:
            raise ValueError('l0 should be lower than h0.')
        if h1 <= l1:
            raise ValueError('l1 should be lower than h1.')

        self._origin = origin
        self._axis0 = axis0
        self._axis1 = axis1
        self._l0 = l0
        self._h0 = h0
        self._l1 = l1
        self._h1 = h1

        size = (h0 - l0 + 1) * (h1 - l1 + 1)
        points = np.zeros((size, 3), float)
        weights = np.empty(size, float)
        weights[:] = np.sqrt((np.linalg.norm(axis0) *
                              np.linalg.norm(axis1))**2 -
                             np.dot(axis0, axis1)**2)
        counter = 0
        for i0 in range(l0, h0 + 1):
            for i1 in range(l1, h1 + 1):
                points[counter] = origin + axis0 * i0 + axis1 * i1
                counter += 1
        IntGrid.__init__(self, points, weights)
Beispiel #4
0
def test_grid_integrate():
    npoint = 10
    grid = IntGrid(np.random.normal(0, 1, (npoint, 3)), np.random.normal(0, 1, npoint))
    pot = np.random.normal(0, 1, npoint)
    dens = np.random.normal(0, 1, npoint)

    # three
    int1 = grid.integrate(pot, dens)
    int2 = (grid.weights * pot * dens).sum()
    assert abs(int1 - int2) < 1e-10

    # two
    int1 = grid.integrate(pot)
    int2 = (grid.weights * pot).sum()
    assert abs(int1 - int2) < 1e-10

    # one
    int1 = grid.integrate()
    int2 = grid.weights.sum()
    assert abs(int1 - int2) < 1e-10
Beispiel #5
0
    def __init__(self,
                 number,
                 pseudo_number,
                 center,
                 agspec='medium',
                 random_rotate=True,
                 points=None):
        """
           **Arguments:**

           number
                The element number for which this grid will be used.

           pseudo_number
                The effective core charge for which this grid will be used.

           center
                The center of the radial grid

           **Optional arguments:**

           agspec
                A specifications of the atomic grid. This can either be an
                instance of the AtomicGridSpec object, or the first argument
                of its constructor.

           random_rotate
                When set to False, the random rotation of the grid points is
                disabled. Such random rotation improves the accuracy of the
                integration, but leads to small random changes in the results
                that are not reproducible.

           points
                Array to store the grid points
        """
        self._number = number
        self._pseudo_number = pseudo_number
        self._center = center
        if not isinstance(agspec, AtomicGridSpec):
            agspec = AtomicGridSpec(agspec)
        self._agspec = agspec
        self._rgrid, self._nlls = self._agspec.get(number, pseudo_number)
        self._random_rotate = random_rotate

        # Obtain the total size and allocate arrays for this grid.
        size = self._nlls.sum()
        if points is None:
            points = np.zeros((size, 3), float)
        else:
            assert len(points) == size
        weights = np.zeros(size, float)

        # Fill the points and weights arrays
        offset = 0
        nsphere = len(self._nlls)
        radii = self._rgrid.radii
        rweights = self._rgrid.weights

        for i in range(nsphere):
            nll = self._nlls[i]
            my_points = points[offset:offset + nll]
            my_weights = weights[offset:offset + nll]

            # lebedev_laikov_sphere(my_points, my_weights)
            sub_points, sub_weights = lebedev_laikov_sphere(len(my_points))
            points[offset:offset + nll] = sub_points
            weights[offset:offset + nll] = sub_weights
            my_points *= radii[i]
            if self.random_rotate:
                rotmat = get_random_rotation()
                my_points[:] = np.dot(my_points, rotmat)
            my_weights *= rweights[i]

            offset += nll

        points[:] += self.center

        IntGrid.__init__(self, points, weights)
        self._log_init()
Beispiel #6
0
    def __init__(self,
                 centers,
                 numbers,
                 pseudo_numbers=None,
                 agspec='medium',
                 k=3,
                 random_rotate=True,
                 mode='discard'):
        """
           **Arguments:**

           centers
                An array (N, 3) with centers for the atom-centered grids.

           numbers
                An array (N,) with atomic numbers.

           **Optional arguments:**

           pseudo_numbers
                An array (N,) with effective core charges. When not given, this
                defaults to ``numbers``.

           agspec
                A specifications of the atomic grid. This can either be an
                instance of the AtomicGridSpec object, or the first argument
                of its constructor.

           k
                The order of the switching function in Becke's weighting scheme.

           random_rotate
                Flag to control random rotation of spherical grids.

           mode
                Select one of the following options regarding atomic subgrids:

                * ``'discard'`` (the default) means that all information about
                  subgrids gets discarded.

                * ``'keep'`` means that a list of subgrids is kept, including
                  the integration weights of the local grids.

                * ``'only'`` means that only the subgrids are constructed and
                  that the computation of the molecular integration weights
                  (based on the Becke partitioning) is skipped.
        """
        natom, centers, numbers, pseudo_numbers = typecheck_geo(
            centers, numbers, pseudo_numbers)
        self._centers = centers
        self._numbers = numbers
        self._pseudo_numbers = pseudo_numbers

        # check if the mode argument is valid
        if mode not in ['discard', 'keep', 'only']:
            raise ValueError(
                'The mode argument must be \'discard\', \'keep\' or \'only\'.')

        # transform agspec into a usable format
        if not isinstance(agspec, AtomicGridSpec):
            agspec = AtomicGridSpec(agspec)
        self._agspec = agspec

        # assign attributes
        self._k = k
        self._random_rotate = random_rotate
        self._mode = mode

        # allocate memory for the grid
        size = sum(
            agspec.get_size(self.numbers[i], self.pseudo_numbers[i])
            for i in range(natom))
        points = np.zeros((size, 3), float)
        weights = np.zeros(size, float)
        self._becke_weights = np.ones(size, float)

        # construct the atomic grids
        if mode != 'discard':
            atgrids = []
        else:
            atgrids = None
        offset = 0

        if mode != 'only':
            # More recent covalent radii are used than in the original work of Becke.
            # No covalent radius is defined for elements heavier than Curium and a
            # default value of 3.0 Bohr is used for heavier elements.
            cov_radii = np.array([(periodic[n].cov_radius or 3.0)
                                  for n in self.numbers])

        # The actual work:
        logging.info('Preparing Becke-Lebedev molecular integration grid.')
        for i in range(natom):
            atsize = agspec.get_size(self.numbers[i], self.pseudo_numbers[i])
            atgrid = AtomicGrid(self.numbers[i], self.pseudo_numbers[i],
                                self.centers[i], agspec, random_rotate,
                                points[offset:offset + atsize])
            if mode != 'only':
                atbecke_weights = self._becke_weights[offset:offset + atsize]
                becke_helper_atom(points[offset:offset + atsize],
                                  atbecke_weights, cov_radii, self.centers, i,
                                  self._k)
                weights[offset:offset +
                        atsize] = atgrid.weights * atbecke_weights
            if mode != 'discard':
                atgrids.append(atgrid)
            offset += atsize

        # finish
        IntGrid.__init__(self, points, weights, atgrids)

        # Some screen info
        self._log_init()
Beispiel #7
0
 def integrate(self, *args, **kwargs):
     if self.mode == 'only':
         raise NotImplementedError(
             'When mode==\'only\', only the subgrids can be used for integration.'
         )
     return IntGrid.integrate(self, *args, **kwargs)