Example #1
0
def evaluate_ehrenfest_hessian(
    one_density_matrix,
    basis,
    points,
    alpha=1,
    beta=0,
    transform=None,
    coord_type="spherical",
    symmetric=False,
):
    r"""Return the Ehrenfest Hessian.

    Ehrenfest Hessian is the gradient of the Ehrenfest force:
    .. math::

        H_{jk}(\mathbf{r}_n | \alpha, \beta)
        =&
        - \frac{\partial}{\partial r_k} F_j(\mathbf{r}_n | \alpha, \beta)\\
        =&
        \alpha
        \sum_i
        \left(
            \frac{\partial^4}{\partial r^2_i \partial r_k \partial r'_j}
            \gamma(\mathbf{r}, \mathbf{r}')
            +\frac{\partial^4}{\partial r^2_i \partial r'_j \partial r'_k}
            \gamma(\mathbf{r}, \mathbf{r}')
        \right)_{\mathbf{r} = \mathbf{r}' = \mathbf{r}_n}\\
        &- (1 - \alpha)
        \sum_i
        \left(
            \frac{\partial^4}{\partial r^2_i \partial r_j \partial r_k}
            \gamma(\mathbf{r}, \mathbf{r})
            + \frac{\partial^4}{\partial r^2_i \partial r_j \partial r'_k}
            \gamma(\mathbf{r}, \mathbf{r})
        \right)_{\mathbf{r} = \mathbf{r}' = \mathbf{r}_n}\\
        &- (1 - 2\alpha)
        \sum_i
        \left(
            \frac{\partial^4}{\partial r_i \partial r_j \partial r_k \partial r'_i}
            \gamma(\mathbf{r}, \mathbf{r})
            + \frac{\partial^4}{\partial r_i \partial r_j \partial r'_i \partial r'_k}
            \gamma(\mathbf{r}, \mathbf{r})
        \right)_{\mathbf{r} = \mathbf{r}' = \mathbf{r}_n}\\
        &+ \frac{1}{2} \beta
        \left.
            \left(
                \frac{\partial^4}{\partial r_j \partial r_k \partial x^2}
                + \frac{\partial^4}{\partial r_j \partial r_k \partial y^2}
                + \frac{\partial^4}{\partial r_j \partial r_k \partial z^2}
            \right)
            \rho(\mathbf{r}_n)
        \right|_{\mathbf{r}=\mathbf{r}_n}\\

    Parameters
    ----------
    one_density_matrix : np.ndarray(K_orb, K_orb)
        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.
    basis : list/tuple of GeneralizedContractionShell
        Shells of generalized contractions.
    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.
    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.
    alpha : {int, float}
        First parameter of the stress tensor.
        Default value is 1.
    beta : {int, float}
        Second parameter of the stress tensor.
        Default value is 0.
    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".
    symmetric : {True, False}
        Flag for symmetrizing the Hessian.
        If True, then the Hessian is symmetrized by averaging it with its transpose.
        Default value is False.

    Returns
    -------
    ehrenfest_hessian : np.ndarray(N, 3, 3)
        Ehrenfest Hessian of the given density matrix evaluated at the given coordinates.
        Hessian is symmetrized if `symmetric` is True.

    Raises
    ------
    TypeError
        If `alpha` is not an integer or float.
        If `beta` is not an integer or float.

    """
    if not isinstance(alpha, (int, float)):
        raise TypeError("`alpha` must be an integer or a float.")
    if not isinstance(beta, (int, float)):
        raise TypeError("`beta` must be an integer or a float.")
    output = np.zeros((3, 3, points.shape[0]))
    for i, orders_two in enumerate(np.identity(3, dtype=int)):
        for j, orders_three in enumerate(np.identity(3, dtype=int)):
            for orders_one in np.identity(3, dtype=int):
                if alpha != 0:
                    output[i,
                           j] += alpha * evaluate_deriv_reduced_density_matrix(
                               2 * orders_one + orders_three,
                               orders_two,
                               one_density_matrix,
                               basis,
                               points,
                               transform=transform,
                               coord_type=coord_type,
                           )
                    output[i,
                           j] += alpha * evaluate_deriv_reduced_density_matrix(
                               2 * orders_one,
                               orders_two + orders_three,
                               one_density_matrix,
                               basis,
                               points,
                               transform=transform,
                               coord_type=coord_type,
                           )
                if alpha != 1:
                    output[i, j] -= (
                        1 - alpha) * evaluate_deriv_reduced_density_matrix(
                            2 * orders_one + orders_two + orders_three,
                            np.array([0, 0, 0]),
                            one_density_matrix,
                            basis,
                            points,
                            transform=transform,
                            coord_type=coord_type,
                        )
                    output[i, j] -= (
                        1 - alpha) * evaluate_deriv_reduced_density_matrix(
                            2 * orders_one + orders_two,
                            orders_three,
                            one_density_matrix,
                            basis,
                            points,
                            transform=transform,
                            coord_type=coord_type,
                        )
                if alpha != 0.5:
                    output[i, j] -= (
                        1 - 2 * alpha) * evaluate_deriv_reduced_density_matrix(
                            orders_one + orders_two + orders_three,
                            orders_one,
                            one_density_matrix,
                            basis,
                            points,
                            transform=transform,
                            coord_type=coord_type,
                        )
                    output[i, j] -= (
                        1 - 2 * alpha) * evaluate_deriv_reduced_density_matrix(
                            orders_one + orders_two,
                            orders_one + orders_three,
                            one_density_matrix,
                            basis,
                            points,
                            transform=transform,
                            coord_type=coord_type,
                        )
                if beta != 0:
                    output[i, j] += (0.5 * beta * evaluate_deriv_density(
                        2 * orders_one + orders_two + orders_three,
                        one_density_matrix,
                        basis,
                        points,
                        transform=transform,
                        coord_type=coord_type,
                    ))
    if symmetric:
        output += np.swapaxes(output, 0, 1)
        output /= 2
    return np.transpose(output, (2, 0, 1))
Example #2
0
def evaluate_stress_tensor(one_density_matrix,
                           basis,
                           points,
                           alpha=1,
                           beta=0,
                           transform=None,
                           coord_type="spherical"):
    r"""Return the stress tensor evaluated at the given coordinates.

    Stress tensor is defined here as:
    .. math::

        \boldsymbol{\sigma}_{ij}(\mathbf{r}_n | \alpha, \beta)
        =&
        -\frac{1}{2} \alpha
        \left(
            \frac{\partial^2}{\partial r_i \partial r'_j} \gamma(\mathbf{r}, \mathbf{r}')
            + \frac{\partial^2}{\partial r_j \partial r'_i} \gamma(\mathbf{r}, \mathbf{r}')
        \right)_{\mathbf{r} = \mathbf{r}' = \mathbf{r}_n}\\
        & +\frac{1}{2} (1 - \alpha)
        \left(
            \frac{\partial^2}{\partial r_i \partial r_j} \gamma(\mathbf{r}, \mathbf{r})
            + \frac{\partial^2}{\partial r'_i \partial r'_j} \gamma(\mathbf{r}, \mathbf{r}')
        \right)_{\mathbf{r} = \mathbf{r}' = \mathbf{r}_n}\\
        & - \frac{1}{2} \delta_{ij} \beta
        \left.
            \nabla^2 \rho(\mathbf{r})
        \right_{\mathbf{r}=\mathbf{r}_n}\\
        =&
        - \alpha
        \left.
            \frac{\partial^2}{\partial r_i \partial r'_j} \gamma(\mathbf{r}, \mathbf{r}')
        \right|_{\mathbf{r} = \mathbf{r}' = \mathbf{r}_n}
        + (1 - \alpha)
        \left.
            \frac{\partial^2}{\partial r_i \partial r_j} \gamma(\mathbf{r}, \mathbf{r})
        \right|_{\mathbf{r} = \mathbf{r}' = \mathbf{r}_n}
        - \frac{1}{2} \delta_{ij} \beta
        \left.
            \nabla^2 \rho(\mathbf{r})
        \right_{\mathbf{r}=\mathbf{r}_n}\\

    Parameters
    ----------
    one_density_matrix : np.ndarray(K_orb, K_orb)
        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.
    basis : list/tuple of GeneralizedContractionShell
        Shells of generalized contractions.
    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.
    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.
    alpha : {int, float}
        First parameter of the stress tensor.
        Default value is 1.
    beta : {int, float}
        Second parameter of the stress tensor.
        Default value is 0.
    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
    -------
    stress_tensor : np.ndarray(N, 3, 3)
        Stress tensor of the given density matrix evaluated at the given points.

    Raises
    ------
    TypeError
        If `alpha` is not an integer or float.
        If `beta` is not an integer or float.

    """
    if not isinstance(alpha, (int, float)):
        raise TypeError("`alpha` must be an integer or a float.")
    if not isinstance(beta, (int, float)):
        raise TypeError("`beta` must be an integer or a float.")
    output = np.zeros((3, 3, points.shape[0]))
    for i, orders_two in enumerate(np.identity(3, dtype=int)):
        for j, orders_one in enumerate(np.identity(3, dtype=int)[i:]):
            j += i
            if alpha != 0:
                output[i, j] -= alpha * evaluate_deriv_reduced_density_matrix(
                    orders_one,
                    orders_two,
                    one_density_matrix,
                    basis,
                    points,
                    transform=transform,
                    coord_type=coord_type,
                )
            if alpha != 1:
                output[i,
                       j] += (1 -
                              alpha) * evaluate_deriv_reduced_density_matrix(
                                  orders_one + orders_two,
                                  np.array([0, 0, 0]),
                                  one_density_matrix,
                                  basis,
                                  points,
                                  transform=transform,
                                  coord_type=coord_type,
                              )
            if i == j and beta != 0:
                output[i, j] -= (0.5 * beta * evaluate_density_laplacian(
                    one_density_matrix,
                    basis,
                    points,
                    transform=transform,
                    coord_type=coord_type,
                ))
            output[j, i] = output[i, j]
    return np.transpose(output, (2, 1, 0))
Example #3
0
def test_evaluate_stress_tensor():
    """Test gbasis.evals.stress_tensor.evaluate_stress_tensor."""
    basis_dict = parse_nwchem(find_datafile("data_anorcc.nwchem"))
    coords = np.array([[0, 0, 0]])
    basis = make_contractions(basis_dict, ["H"], coords)
    points = np.random.rand(10, 3)

    with pytest.raises(TypeError):
        evaluate_stress_tensor(np.identity(40), basis, points, np.array(0), 0,
                               np.identity(40))
    with pytest.raises(TypeError):
        evaluate_stress_tensor(np.identity(40), basis, points, 1, None,
                               np.identity(40))
    with pytest.raises(TypeError):
        evaluate_stress_tensor(np.identity(40), basis, points, 1, 0j,
                               np.identity(40))

    test_a = evaluate_stress_tensor(np.identity(40), basis, points, 0, 0,
                                    np.identity(40))
    test_b = evaluate_stress_tensor(np.identity(40), basis, points, 1, 0,
                                    np.identity(40))
    test_c = evaluate_stress_tensor(np.identity(40), basis, points, 1, 2,
                                    np.identity(40))
    test_d = evaluate_stress_tensor(np.identity(40), basis, points, 0.5, 2,
                                    np.identity(40))
    for i in range(3):
        for j in range(3):
            orders_i = np.array([0, 0, 0])
            orders_i[i] += 1
            orders_j = np.array([0, 0, 0])
            orders_j[j] += 1

            temp1 = evaluate_deriv_reduced_density_matrix(
                orders_i, orders_j, np.identity(40), basis, points,
                np.identity(40))
            temp2 = evaluate_deriv_reduced_density_matrix(
                orders_j, orders_i, np.identity(40), basis, points,
                np.identity(40))
            temp3 = evaluate_deriv_reduced_density_matrix(
                orders_i + orders_j,
                np.array([0, 0, 0]),
                np.identity(40),
                basis,
                points,
                np.identity(40),
            )
            temp4 = evaluate_deriv_reduced_density_matrix(
                orders_i + orders_j,
                np.array([0, 0, 0]),
                np.identity(40),
                basis,
                points,
                np.identity(40),
            )
            if i == j:
                temp5 = evaluate_density_laplacian(np.identity(40), basis,
                                                   points, np.identity(40))
            else:
                temp5 = 0
            assert np.allclose(test_a[:, i, j], 0.5 * temp3 + 0.5 * temp4)
            assert np.allclose(test_b[:, i, j], -0.5 * temp1 - 0.5 * temp2)
            assert np.allclose(test_c[:, i, j],
                               -0.5 * temp1 - 0.5 * temp2 - temp5)
            assert np.allclose(
                test_d[:, i, j], -0.25 * temp1 - 0.25 * temp2 + 0.25 * temp3 +
                0.25 * temp4 - temp5)
Example #4
0
def test_evaluate_ehrenfest_force():
    """Test gbasis.evals.stress_tensor.evaluate_ehrenfest_force."""
    basis_dict = parse_nwchem(find_datafile("data_anorcc.nwchem"))
    coords = np.array([[0, 0, 0]])
    basis = make_contractions(basis_dict, ["H"], coords)
    points = np.random.rand(10, 3)

    with pytest.raises(TypeError):
        evaluate_ehrenfest_force(np.identity(40), basis, points, np.array(0),
                                 0, np.identity(40))
    with pytest.raises(TypeError):
        evaluate_ehrenfest_force(np.identity(40), basis, points, 1, None,
                                 np.identity(40))
    with pytest.raises(TypeError):
        evaluate_ehrenfest_force(np.identity(40), basis, points, 1, 0j,
                                 np.identity(40))

    test_a = evaluate_ehrenfest_force(np.identity(40), basis, points, 0, 0,
                                      np.identity(40))
    test_b = evaluate_ehrenfest_force(np.identity(40), basis, points, 1, 0,
                                      np.identity(40))
    test_c = evaluate_ehrenfest_force(np.identity(40), basis, points, 0.5, 0,
                                      np.identity(40))
    test_d = evaluate_ehrenfest_force(np.identity(40), basis, points, 0, 2,
                                      np.identity(40))
    for j in range(3):
        ref_a = np.zeros(points.shape[0])
        ref_b = np.zeros(points.shape[0])
        ref_c = np.zeros(points.shape[0])
        ref_d = np.zeros(points.shape[0])

        orders_j = np.array([0, 0, 0])
        orders_j[j] += 1
        for i in range(3):
            orders_i = np.array([0, 0, 0])
            orders_i[i] += 1

            temp1 = evaluate_deriv_reduced_density_matrix(
                2 * orders_i, orders_j, np.identity(40), basis, points,
                np.identity(40))
            temp2 = evaluate_deriv_reduced_density_matrix(
                orders_i, orders_i + orders_j, np.identity(40), basis, points,
                np.identity(40))
            temp3 = evaluate_deriv_reduced_density_matrix(
                2 * orders_i + orders_j,
                np.array([0, 0, 0]),
                np.identity(40),
                basis,
                points,
                np.identity(40),
            )
            temp4 = evaluate_deriv_reduced_density_matrix(
                orders_i + orders_j, orders_i, np.identity(40), basis, points,
                np.identity(40))
            temp5 = evaluate_deriv_density(2 * orders_i + orders_j,
                                           np.identity(40), basis, points,
                                           np.identity(40))

            ref_a += temp3 + temp4
            ref_b += -temp1 - temp2
            ref_c += -0.5 * temp1 - 0.5 * temp2 + 0.5 * temp3 + 0.5 * temp4
            ref_d += temp3 + temp4 - temp5
        assert np.allclose(test_a[:, j], ref_a)
        assert np.allclose(test_b[:, j], ref_b)
        assert np.allclose(test_c[:, j], ref_c)
        assert np.allclose(test_d[:, j], ref_d)
Example #5
0
def test_evaluate_ehrenfest_hessian():
    """Test gbasis.evals.stress_tensor.evaluate_ehrenfest_hessian."""
    basis_dict = parse_nwchem(find_datafile("data_anorcc.nwchem"))
    coords = np.array([[0, 0, 0]])
    basis = make_contractions(basis_dict, ["H"], coords)
    basis = [
        HortonContractions(i.angmom, i.coord, i.coeffs, i.exps) for i in basis
    ]

    points = np.random.rand(10, 3)

    with pytest.raises(TypeError):
        evaluate_ehrenfest_hessian(np.identity(40), basis, points, np.array(0),
                                   0, np.identity(40))
    with pytest.raises(TypeError):
        evaluate_ehrenfest_hessian(np.identity(40), basis, points, 1, None,
                                   np.identity(40))
    with pytest.raises(TypeError):
        evaluate_ehrenfest_hessian(np.identity(40), basis, points, 1, 0j,
                                   np.identity(40))

    test_a = evaluate_ehrenfest_hessian(np.identity(40), basis, points, 0, 0,
                                        np.identity(40))
    test_b = evaluate_ehrenfest_hessian(np.identity(40), basis, points, 1, 0,
                                        np.identity(40))
    test_c = evaluate_ehrenfest_hessian(np.identity(40), basis, points, 0.5, 0,
                                        np.identity(40))
    test_d = evaluate_ehrenfest_hessian(np.identity(40), basis, points, 0, 2,
                                        np.identity(40))
    for j in range(3):
        for k in range(3):
            ref_a = np.zeros(points.shape[0])
            ref_b = np.zeros(points.shape[0])
            ref_c = np.zeros(points.shape[0])
            ref_d = np.zeros(points.shape[0])

            orders_j = np.array([0, 0, 0])
            orders_j[j] += 1
            orders_k = np.array([0, 0, 0])
            orders_k[k] += 1
            for i in range(3):
                orders_i = np.array([0, 0, 0])
                orders_i[i] += 1

                temp1 = evaluate_deriv_reduced_density_matrix(
                    2 * orders_i + orders_k,
                    orders_j,
                    np.identity(40),
                    basis,
                    points,
                    np.identity(40),
                )
                temp2 = evaluate_deriv_reduced_density_matrix(
                    2 * orders_i,
                    orders_j + orders_k,
                    np.identity(40),
                    basis,
                    points,
                    np.identity(40),
                )
                temp3 = evaluate_deriv_reduced_density_matrix(
                    orders_i + orders_k,
                    orders_i + orders_j,
                    np.identity(40),
                    basis,
                    points,
                    np.identity(40),
                )
                temp4 = evaluate_deriv_reduced_density_matrix(
                    orders_i,
                    orders_i + orders_j + orders_k,
                    np.identity(40),
                    basis,
                    points,
                    np.identity(40),
                )
                temp5 = evaluate_deriv_reduced_density_matrix(
                    2 * orders_i + orders_j + orders_k,
                    np.array([0, 0, 0]),
                    np.identity(40),
                    basis,
                    points,
                    np.identity(40),
                )
                temp6 = evaluate_deriv_reduced_density_matrix(
                    2 * orders_i + orders_j,
                    orders_k,
                    np.identity(40),
                    basis,
                    points,
                    np.identity(40),
                )
                temp7 = evaluate_deriv_reduced_density_matrix(
                    orders_i + orders_j + orders_k,
                    orders_i,
                    np.identity(40),
                    basis,
                    points,
                    np.identity(40),
                )
                temp8 = evaluate_deriv_reduced_density_matrix(
                    orders_i + orders_j,
                    orders_i + orders_k,
                    np.identity(40),
                    basis,
                    points,
                    np.identity(40),
                )
                temp9 = evaluate_deriv_density(
                    2 * orders_i + orders_j + orders_k,
                    np.identity(40),
                    basis,
                    points,
                    np.identity(40),
                )

                ref_a += temp5 + temp6 + temp7 + temp8
                ref_b += -temp1 - temp2 - temp3 - temp4
                ref_c += (-0.5 * temp1 - 0.5 * temp2 - 0.5 * temp3 -
                          0.5 * temp4 + 0.5 * temp5 + 0.5 * temp6 +
                          0.5 * temp7 + 0.5 * temp8)
                ref_d += temp3 + temp4 + temp5 + temp6 - temp9
            assert np.allclose(test_a[:, j, k], ref_a)
            assert np.allclose(test_b[:, j, k], ref_b)
            assert np.allclose(test_c[:, j, k], ref_c)
            assert np.allclose(test_d[:, j, k], ref_d)
    assert np.allclose(
        evaluate_ehrenfest_hessian(np.identity(40),
                                   basis,
                                   points,
                                   0,
                                   0,
                                   np.identity(40),
                                   symmetric=True),
        (evaluate_ehrenfest_hessian(np.identity(40), basis, points, 0, 0,
                                    np.identity(40)) +
         np.swapaxes(
             evaluate_ehrenfest_hessian(np.identity(40), basis, points, 0, 0,
                                        np.identity(40)),
             1,
             2,
         )) / 2,
    )