Coverage for strongcoca / calculators / utilities.py: 100%
10 statements
« prev ^ index » next coverage.py v7.13.4, created at 2026-04-15 18:15 +0000
« prev ^ index » next coverage.py v7.13.4, created at 2026-04-15 18:15 +0000
1import numpy as np
4def get_dipole_dipole_tensor(distance_vector: np.ndarray) -> np.ndarray:
5 r"""Returns the dipole-dipole tensor. The dipole-dipole tensor is defined as
7 .. math:
9 T_{i\mu j\nu} = \nabla_\mu \nabla_\nu \frac{1}{|\vec{R_{ij}}|}
10 = \frac{\delta_{\mu\nu}}{|\vec{R_{ij}}|^3}
11 - 3 \frac{R_{ij,\mu} R_{ij,\nu}}{|\vec{R_{ij}}|^5}
13 Parameters
14 ----------
15 distance_vector
16 Distance vector between the two subsystems.
18 Example
19 -------
21 .. doctest:
23 >>> get_dipole_dipole_tensor(np.array([1, 2, 3]))
24 array([[ 0.01499936, -0.00818147, -0.0122722 ],
25 [-0.00818147, 0.00272716, -0.0245444 ],
26 [-0.0122722 , -0.0245444 , -0.01772651]])
28 """
29 assert distance_vector.shape == (3,), \
30 f'distance_vector has the wrong shape ({distance_vector})'
31 r = np.linalg.norm(distance_vector)
32 T = np.eye(3) / r ** 3 - 3 * np.outer(distance_vector, distance_vector) / r ** 5
33 return T # type: ignore
36def logm_batched(A_wnn: np.ndarray) -> np.ndarray:
37 """Batched matrix logarithm via eigendecomposition.
39 Computes ``log(A)`` for each matrix in a batch using the decomposition
40 ``A = V diag(λ) V⁻¹ → log(A) = V diag(log λ) V⁻¹``.
42 Parameters
43 ----------
44 A_wnn
45 Batch of square matrices, shape (W, N, N). Complex inputs supported.
47 Returns
48 -------
49 :class:`np.ndarray`
50 Array of the same shape as *A_wnn*.
52 Notes
53 -----
54 Uses the principal value of the logarithm, identical to
55 ``scipy.linalg.logm`` for matrices without eigenvalues on the negative
56 real axis.
58 Examples
59 --------
61 >>> import numpy as np
62 >>> from strongcoca.calculators.utilities import logm_batched
63 >>> A = np.array([[[2., 0.], [0., 4.]]])
64 >>> np.allclose(logm_batched(A), [[[np.log(2), 0.], [0., np.log(4)]]])
65 True
66 """
67 eigvals_wn, eigvecs_wnn = np.linalg.eig(A_wnn)
68 log_eigvals_wn = np.log(eigvals_wn)
69 # logm(A) = V @ diag(log λ) @ V⁻¹; scale each column of V by its log-eigenvalue
70 return (eigvecs_wnn * log_eigvals_wn[:, None, :]) @ np.linalg.inv(eigvecs_wnn)