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))
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, )
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)
def test_evaluate_deriv_density(): """Test gbasis.evals.density.evaluate_deriv_density.""" basis_dict = parse_nwchem(find_datafile("data_sto6g.nwchem")) basis = make_contractions(basis_dict, ["Kr"], np.array([[0, 0, 0]])) transform = np.random.rand(14, 18) density = np.random.rand(14, 14) density += density.T points = np.random.rand(10, 3) assert np.allclose( evaluate_deriv_density(np.array([1, 0, 0]), density, basis, points, transform), np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([1, 0, 0]), transform), evaluate_basis(basis, points, transform), ) + np.einsum( "ij,ik,jk->k", density, evaluate_basis(basis, points, transform), evaluate_deriv_basis(basis, points, np.array([1, 0, 0]), transform), ), ) assert np.allclose( evaluate_deriv_density(np.array([0, 1, 0]), density, basis, points, transform), np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([0, 1, 0]), transform), evaluate_basis(basis, points, transform), ) + np.einsum( "ij,ik,jk->k", density, evaluate_basis(basis, points, transform), evaluate_deriv_basis(basis, points, np.array([0, 1, 0]), transform), ), ) assert np.allclose( evaluate_deriv_density(np.array([0, 0, 1]), density, basis, points, transform), np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([0, 0, 1]), transform), evaluate_basis(basis, points, transform), ) + np.einsum( "ij,ik,jk->k", density, evaluate_basis(basis, points, transform), evaluate_deriv_basis(basis, points, np.array([0, 0, 1]), transform), ), ) assert np.allclose( evaluate_deriv_density(np.array([2, 3, 0]), density, basis, points, transform), np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([0, 0, 0]), transform), evaluate_deriv_basis(basis, points, np.array([2, 3, 0]), transform), ) + 3 * np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([0, 1, 0]), transform), evaluate_deriv_basis(basis, points, np.array([2, 2, 0]), transform), ) + 3 * np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([0, 2, 0]), transform), evaluate_deriv_basis(basis, points, np.array([2, 1, 0]), transform), ) + np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([0, 3, 0]), transform), evaluate_deriv_basis(basis, points, np.array([2, 0, 0]), transform), ) + 2 * np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([1, 0, 0]), transform), evaluate_deriv_basis(basis, points, np.array([1, 3, 0]), transform), ) + 2 * 3 * np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([1, 1, 0]), transform), evaluate_deriv_basis(basis, points, np.array([1, 2, 0]), transform), ) + 2 * 3 * np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([1, 2, 0]), transform), evaluate_deriv_basis(basis, points, np.array([1, 1, 0]), transform), ) + 2 * np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([1, 3, 0]), transform), evaluate_deriv_basis(basis, points, np.array([1, 0, 0]), transform), ) + np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([2, 0, 0]), transform), evaluate_deriv_basis(basis, points, np.array([0, 3, 0]), transform), ) + 3 * np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([2, 1, 0]), transform), evaluate_deriv_basis(basis, points, np.array([0, 2, 0]), transform), ) + 3 * np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([2, 2, 0]), transform), evaluate_deriv_basis(basis, points, np.array([0, 1, 0]), transform), ) + np.einsum( "ij,ik,jk->k", density, evaluate_deriv_basis(basis, points, np.array([2, 3, 0]), transform), evaluate_deriv_basis(basis, points, np.array([0, 0, 0]), transform), ), )