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)
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
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)
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
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()
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()
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)