예제 #1
0
def test_Alchemical_tools_energy_variation():
    PT_CHARGE_INT = point_charge_integral(basis,
                                          R,
                                          q,
                                          transform=molecule.mo.coeffs.T,
                                          coord_type="cartesian")
    dE_1 = 0.0
    for i_c, i in enumerate(molecule.mo.occs):
        if i != 0:
            dE_1 = dE_1 + PT_CHARGE_INT[i_c][i_c][0]
    dE_2_hf = 0.0
    dE_2_lda = 0.0
    for s in range(2):
        for i_c, i in enumerate(occupied_ind[s]):
            for a_c, a in enumerate(virtual_ind[s]):
                ias = (s * len(occupied_ind[0]) * len(virtual_ind[0]) +
                       i_c * len(virtual_ind[s]) + a_c)
                for t in range(2):
                    for j_c, j in enumerate(occupied_ind[t]):
                        for b_c, b in enumerate(virtual_ind[t]):
                            jbt = (t * len(occupied_ind[0]) *
                                   len(virtual_ind[0]) +
                                   j_c * len(virtual_ind[t]) + b_c)
                            dv_ias = PT_CHARGE_INT[a][i][0]
                            dv_jbt = PT_CHARGE_INT[b][j][0]
                            dE_2_hf = dE_2_hf - dv_ias * dv_jbt * M_HF_inv[
                                ias][jbt]
                            dE_2_lda = dE_2_lda - dv_ias * dv_jbt * M_LDA_inv[
                                ias][jbt]
    assert np.allclose(alc_hf.energy_variation(), np.array([dE_1, dE_2_hf]))
    assert np.allclose(alc_lda.energy_variation(), np.array([dE_1, dE_2_lda]))
예제 #2
0
    def energy_variation(self):
        """Return  the variation of the MO energies

        Return
        ------
        dE: 2D ndarray
            dE[0] is the first order energy variation
            dE[1] is the second order energy variation"""
        M_inv = self.M_inverse
        dv = np.sum(
            point_charge_integral(
                self._basis,
                self._pos,
                self._val,
                transform=self._molecule.mo.coeffs.T,
                coord_type=self._coord_type,
            ),
            axis=-1,
        )
        indices = self.K_indices()
        dE = np.sum(np.diag(dv) * self._molecule.mo.occs)
        dv = np.array([
            dv[indices[0][0]][:, indices[1][0]],
            dv[indices[0][1]][:, indices[1][1]]
        ]).reshape([2 * self.M_block_size])
        dE = np.array(
            [dE, -np.dot(dv[:, None].T, M_inv).dot(dv[:, None])[0, 0]])
        return dE
예제 #3
0
def test_point_charge_mix():
    """Test gbasis.integrals.point_charge.point_charge_mix."""
    basis_dict = parse_nwchem(find_datafile("data_sto6g.nwchem"))
    basis = make_contractions(basis_dict, ["Kr"], np.array([[0, 0, 0]]))
    point_charge_obj = PointChargeIntegral(basis)

    points_coords = np.random.rand(5, 3)
    points_charge = np.random.rand(5)
    assert np.allclose(
        point_charge_obj.construct_array_mix(
            ["spherical"] * 8, points_coords=points_coords, points_charge=points_charge
        ),
        point_charge_integral(basis, points_coords, points_charge, coord_type=["spherical"] * 8),
    )
예제 #4
0
def test_Alchemical_tools_density_matrix_variation():

    PT_CHARGE_INT = point_charge_integral(basis,
                                          R,
                                          q,
                                          transform=molecule.mo.coeffs.T,
                                          coord_type="cartesian")
    dP_hf = np.array([np.diag(molecule.mo.occsa), np.diag(molecule.mo.occsb)])
    dP_hf = 0 * dP_hf
    dP_lda = 0 * dP_hf
    for s in range(2):
        for i_c, i in enumerate(occupied_ind[s]):
            for a_c, a in enumerate(virtual_ind[s]):
                ias = (s * len(occupied_ind[0]) * len(virtual_ind[0]) +
                       i_c * len(virtual_ind[s]) + a_c)
                for t in range(2):
                    for j_c, j in enumerate(occupied_ind[t]):
                        for b_c, b in enumerate(virtual_ind[t]):
                            jbt = (t * len(occupied_ind[0]) *
                                   len(virtual_ind[0]) +
                                   j_c * len(virtual_ind[t]) + b_c)
                            dv_ias = PT_CHARGE_INT[a][i][0]
                            if t == 0:
                                dP_hf[t][j][b] = (dP_hf[t][j][b] -
                                                  M_HF_inv[ias][jbt] * dv_ias)
                                dP_hf[t][b][j] = (dP_hf[t][b][j] -
                                                  M_HF_inv[ias][jbt] * dv_ias)
                                dP_lda[t][j][b] = (
                                    dP_lda[t][j][b] -
                                    M_LDA_inv[ias][jbt] * dv_ias)
                                dP_lda[t][b][j] = (
                                    dP_lda[t][b][j] -
                                    M_LDA_inv[ias][jbt] * dv_ias)
                            if t == 1:
                                dP_hf[t][j - 19][b - 19] = (
                                    dP_hf[t][j - 19][b - 19] -
                                    M_HF_inv[ias][jbt] * dv_ias)
                                dP_hf[t][b - 19][j - 19] = (
                                    dP_hf[t][b - 19][j - 19] -
                                    M_HF_inv[ias][jbt] * dv_ias)
                                dP_lda[t][j - 19][b - 19] = (
                                    dP_lda[t][j - 19][b - 19] -
                                    M_LDA_inv[ias][jbt] * dv_ias)
                                dP_lda[t][b - 19][j - 19] = (
                                    dP_lda[t][b - 19][j - 19] -
                                    M_LDA_inv[ias][jbt] * dv_ias)
    assert np.allclose(alc_hf.density_matrix_variation(), dP_hf)
    assert np.allclose(alc_lda.density_matrix_variation(), dP_lda)
예제 #5
0
    def density_matrix_variation(self):
        """Return density matrix variation in MO basis

        Return
        ------
        dP: 3D ndarray
            dP[0] is the alpha density matrix variation
            dP[1] is the beta density matrix variation"""
        M_inv = self.M_inverse
        dv = np.sum(
            point_charge_integral(
                self._basis,
                self._pos,
                self._val,
                transform=self._molecule.mo.coeffs.T,
                coord_type=self._coord_type,
            ),
            axis=-1,
        )
        indices = self.K_indices()
        dv = np.array([
            dv[indices[0][0]][:, indices[1][0]].reshape([self.M_block_size]),
            dv[indices[0][1]][:, indices[1][1]].reshape([self.M_block_size]),
        ]).reshape([2 * self.M_block_size])
        dP = -np.dot(M_inv, dv)
        dP = np.array([
            dP[:self.M_block_size].reshape(
                [len(indices[0][0]), len(indices[1][0])]),
            dP[self.M_block_size:].reshape(
                [len(indices[0][0]), len(indices[1][0])]),
        ])
        dP = np.array([
            np.block([
                [np.zeros([len(indices[0][0]),
                           len(indices[0][0])]), dP[0]],
                [dP[0].T,
                 np.zeros([len(indices[1][0]),
                           len(indices[1][0])])],
            ]),
            np.block([
                [np.zeros([len(indices[0][1]),
                           len(indices[0][1])]), dP[1]],
                [dP[1].T,
                 np.zeros([len(indices[1][1]),
                           len(indices[1][1])])],
            ]),
        ])
        return dP
예제 #6
0
def test_point_charge_lincomb():
    """Test gbasis.integrals.point_charge.point_charge_lincomb."""
    basis_dict = parse_nwchem(find_datafile("data_sto6g.nwchem"))
    basis = make_contractions(basis_dict, ["Kr"], np.array([[0, 0, 0]]))
    point_charge_obj = PointChargeIntegral(basis)

    points_coords = np.random.rand(5, 3)
    points_charge = np.random.rand(5)
    transform = np.random.rand(14, 18)
    assert np.allclose(
        point_charge_obj.construct_array_lincomb(
            transform, "spherical", points_coords=points_coords, points_charge=points_charge
        ),
        point_charge_integral(
            basis, points_coords=points_coords, points_charge=points_charge, transform=transform
        ),
    )
def nuclear_electron_attraction_integral(basis,
                                         nuclear_coords,
                                         nuclear_charges,
                                         transform=None,
                                         coord_type="spherical"):
    """Return the nuclear electron attraction integrals of the basis set in the Cartesian form.

    Parameters
    ----------
    basis : list/tuple of GeneralizedContractionShell
        Contracted Cartesian Gaussians (of the same shell) that will be used to construct an array.
    nuclear_coords : np.ndarray(N_nuc, 3)
        Coordinates of each atom.
    nuclear_charges : np.ndarray(N_nuc)
        Charges of each atom.
    transform : np.ndarray(K, K_cont)
        Transformation matrix from the basis set in the given coordinate system (e.g. AO) to linear
        combinations of contractions (e.g. MO).
        Transformation is applied to the left, i.e. the sum is over the index 1 of `transform`
        and index 0 of the array for contractions.
        Default is no transformation.
    coord_type : {"cartesian", list/tuple of "cartesian" or "spherical", "spherical"}
        Types of the coordinate system for the contractions.
        If "cartesian", then all of the contractions are treated as Cartesian contractions.
        If "spherical", then all of the contractions are treated as spherical contractions.
        If list/tuple, then each entry must be a "cartesian" or "spherical" to specify the
        coordinate type of each `GeneralizedContractionShell` instance.
        Default value is "spherical".

    Returns
    -------
    array : np.ndarray(K_cart, K_cart)
        Array associated with the given set of contracted Cartesian Gaussians.
        Dimensions 0 and 1 are associated with the contracted Cartesian
        Gaussians. `K_cart` is the total number of Cartesian contractions within the instance.

    """
    return np.sum(
        point_charge_integral(basis,
                              nuclear_coords,
                              nuclear_charges,
                              transform=transform,
                              coord_type=coord_type),
        axis=2,
    )
예제 #8
0
def test_point_charge_cartesian():
    """Test gbasis.integrals.point_charge.point_charge_cartesian."""
    basis_dict = parse_nwchem(find_datafile("data_sto6g.nwchem"))
    basis = make_contractions(basis_dict, ["Kr"], np.array([[0, 0, 0]]))
    point_charge_obj = PointChargeIntegral(basis)

    points_coords = np.random.rand(5, 3)
    points_charges = np.random.rand(5)
    assert np.allclose(
        point_charge_obj.construct_array_cartesian(
            points_coords=points_coords, points_charges=points_charges),
        point_charge_integral(
            basis,
            points_coords=points_coords,
            points_charges=points_charges,
            coord_type="cartesian",
        ),
    )
예제 #9
0
def test_nuclear_electron_attraction_spherical():
    """Test gbasis.integrals.nuclear_electron_attraction.nuclear_electron_attraction_spherical."""
    basis_dict = parse_nwchem(find_datafile("data_sto6g.nwchem"))
    basis = make_contractions(basis_dict, ["Kr"], np.array([[0, 0, 0]]))

    nuclear_coords = np.random.rand(5, 3)
    nuclear_charges = np.random.rand(5)
    ref = point_charge_integral(basis,
                                nuclear_coords,
                                nuclear_charges,
                                coord_type="spherical")
    assert np.allclose(
        ref[:, :, 0] + ref[:, :, 1] + ref[:, :, 2] + ref[:, :, 3] +
        ref[:, :, 4],
        nuclear_electron_attraction_integral(basis,
                                             nuclear_coords,
                                             nuclear_charges,
                                             coord_type="spherical"),
    )
예제 #10
0
def test_nuclear_electron_attraction_lincomb():
    """Test gbasis.integrals.nuclear_electron_attraction.nuclear_electron_attraction_lincomb."""
    basis_dict = parse_nwchem(find_datafile("data_sto6g.nwchem"))
    basis = make_contractions(basis_dict, ["Kr"], np.array([[0, 0, 0]]))

    nuclear_coords = np.random.rand(5, 3)
    nuclear_charges = np.random.rand(5)
    transform = np.random.rand(14, 18)
    ref = point_charge_integral(basis,
                                nuclear_coords,
                                nuclear_charges,
                                transform=transform)
    assert np.allclose(
        ref[:, :, 0] + ref[:, :, 1] + ref[:, :, 2] + ref[:, :, 3] +
        ref[:, :, 4],
        nuclear_electron_attraction_integral(basis,
                                             nuclear_coords,
                                             nuclear_charges,
                                             transform=transform),
    )
예제 #11
0
def nuclear_electron_attraction_integral(basis,
                                         nuclear_coords,
                                         nuclear_charges,
                                         transform=None,
                                         coord_type="spherical"):
    """Return the nuclear electron attraction integrals of the basis set in the Cartesian form.

    Parameters
    ----------
    basis : list/tuple of GeneralizedContractionShell
        Contracted Cartesian Gaussians (of the same shell) that will be used to construct an array.
    nuclear_coords : np.ndarray(N_nuc, 3)
        Coordinates of each atom.
    nuclear_charges : np.ndarray(N_nuc)
        Charges of each atom.
    coord_type : {"cartesian", list/tuple of "cartesian" or "spherical", "spherical"}
        Types of the coordinate system for the contractions.
        If "cartesian", then all of the contractions are treated as Cartesian contractions.
        If "spherical", then all of the contractions are treated as spherical contractions.
        If list/tuple, then each entry must be a "cartesian" or "spherical" to specify the
        coordinate type of each GeneralizedContractionShell instance.
        Default value is "spherical".

    Returns
    -------
    array : np.ndarray(K_cart, K_cart)
        Array associated with the given set of contracted Cartesian Gaussians.
        First and second indices of the array are associated with the contracted Cartesian
        Gaussians. `K_cart` is the total number of Cartesian contractions within the instance.

    """
    return np.sum(
        point_charge_integral(basis,
                              nuclear_coords,
                              nuclear_charges,
                              transform=transform,
                              coord_type=coord_type),
        axis=2,
    )
예제 #12
0
def electrostatic_potential(
    basis,
    one_density_matrix,
    points,
    nuclear_coords,
    nuclear_charges,
    transform=None,
    coord_type="spherical",
    threshold_dist=0.0,
):
    r"""Return the electrostatic potentials of the basis set in the Cartesian form.

    Parameters
    ----------
    basis : list/tuple of GeneralizedContractionShell
        Shells of generalized contractions.
    one_density_matrix : np.ndarray(K_orbs, K_orbs)
        One-electron density matrix in terms of the given basis set.
        If the basis is transformed using `transform` keyword, then the density matrix is assumed
        to be expressed with respect to the transformed basis set.
    points : np.ndarray(N, 3)
        Cartesian coordinates of the points in space (in atomic units) where the basis functions
        are evaluated.
        Rows correspond to the points and columns correspond to the :math:`x, y, \text{and} z`
        components.
    nuclear_coords : np.ndarray(N_nuc, 3)
        Cartesian coordinates of each atom.
        Rows correspond to the atoms and columns correspond to the :math:`x, y, \text{and} z`
        components.
    nuclear_charges : np.ndarray(N_nuc)
        Charges of each atom.
    transform : np.ndarray(K_orbs, K_cont)
        Transformation matrix from the basis set in the given coordinate system (e.g. AO) to linear
        combinations of contractions (e.g. MO).
        Transformation is applied to the left, i.e. the sum is over the index 1 of `transform`
        and index 0 of the array for contractions.
        Default is no transformation.
    coord_type : {"cartesian", "spherical", list/tuple of "cartesian" or "spherical"}
        Types of the coordinate system for the contractions.
        If "cartesian", then all of the contractions are treated as Cartesian contractions.
        If "spherical", then all of the contractions are treated as spherical contractions.
        If list/tuple, then each entry must be a "cartesian" or "spherical" to specify the
        coordinate type of each `GeneralizedContractionShell` instance.
    threshold_dist : {float, 0.0}
        Threshold for rejecting nuclei whose distances to the points are less than the provided
        value. i.e. nuclei that are closer to the point than the threshold are discarded when
        computing the electrostatic potential of the point.
        Default value is 0.0, i.e. no nuclei are discarded.

    Returns
    -------
    array : np.ndarray(N)
        Electrostatic potential evaluated at the given points.

    Raises
    ------
    TypeError
        If `one_density_matrix` is not a two-dimensional `numpy` array.
        If `nuclear_coords` is not a two-dimensional `numpy` array with 3 columns.
        If `nuclear_charges` is not a one-dimensional `numpy` array.
        If `threshold_dist` is not an integer or float.
    ValueError
        If `one_density_matrix` is not a symmetric (square) matrix.
        If number of rows in `nuclear_coords` is not equal to the number of elements in
        `nuclear_charges`.
        If `threshold_dist` is less than 0.

    """
    # pylint: disable=R0912
    if not (isinstance(one_density_matrix, np.ndarray)
            and one_density_matrix.ndim == 2):
        raise TypeError(
            "`one_density_matrix_cart` must be given as a two-dimensional `numpy` array."
        )
    if not (isinstance(nuclear_coords, np.ndarray) and nuclear_coords.ndim == 2
            and nuclear_coords.shape[1] == 3):
        raise TypeError(
            "`nuclear_coords` must be a two-dimensional `numpy` array with 3 columns."
        )
    if not (isinstance(nuclear_charges, np.ndarray)
            and nuclear_charges.ndim == 1):
        raise TypeError(
            "`nuclear_charges` must be a one-dimensional `numpy` array.")

    if not (one_density_matrix.shape[0] == one_density_matrix.shape[1]
            and np.allclose(one_density_matrix, one_density_matrix.T)):
        raise ValueError(
            "`one_density_matrix_cart` must be a symmetric (square) matrix.")
    if nuclear_coords.shape[0] != nuclear_charges.size:
        raise ValueError(
            "Number of rows in `nuclear_coords` must be equal to the number of elements in "
            "`nuclear_charges`.")
    if not isinstance(threshold_dist, (int, float)):
        raise TypeError("`threshold_dist` must be an integer or float.")
    if threshold_dist < 0:
        raise ValueError(
            "`threshold_dist` must be greater than or equal to zero.")

    if coord_type == "cartesian":
        if sum(cont.num_cart * cont.num_seg_cont
               for cont in basis) != one_density_matrix.shape[0]:
            raise ValueError(
                "`one_density_matrix` does not have number of rows/columns that is equal to the "
                "total number of Cartesian contractions (atomic orbitals).")
    elif coord_type == "spherical":
        if sum(cont.num_sph * cont.num_seg_cont
               for cont in basis) != one_density_matrix.shape[0]:
            raise ValueError(
                "`one_density_matrix` does not have number of rows/columns that is equal to the "
                "total number of spherical contractions (atomic orbitals).")
    elif isinstance(coord_type, (list, tuple)):
        if (sum(cont.num_sph *
                cont.num_seg_cont if j == "spherical" else cont.num_cart *
                cont.num_seg_cont for cont, j in zip(basis, coord_type)) !=
                one_density_matrix.shape[0]):
            raise ValueError(
                "`one_density_matrix` does not have number of rows/columns that is equal to the "
                "total number of contractions in the given coordinate systems (atomic orbitals)."
            )
    else:
        raise TypeError(
            "`coord_type` must be 'spherical', 'cartesian', or a list/tuple of these strings."
        )
    hartree_potential = point_charge_integral(basis,
                                              points,
                                              -np.ones(points.shape[0]),
                                              transform=transform,
                                              coord_type=coord_type)
    hartree_potential *= one_density_matrix[:, :, None]
    hartree_potential = np.sum(hartree_potential, axis=(0, 1))

    # silence warning for dividing by zero
    old_settings = np.seterr(divide="ignore")
    external_potential = (nuclear_charges[None, :] / np.sum(
        (points[:, :, None] - nuclear_coords.T[None, :, :])**2, axis=1)**0.5)
    # zero out potentials of elements that are too close to the nucleus
    external_potential[external_potential > 1.0 / np.array(threshold_dist)] = 0
    # restore old settings
    np.seterr(**old_settings)
    # sum over potentials for each dimension
    external_potential = -np.sum(external_potential, axis=1)

    return -(external_potential + hartree_potential)