|
| 1 | +--- |
| 2 | +title: Spherical Harmonics |
| 3 | +date: 2025-02-15 |
| 4 | +math: true |
| 5 | +image: |
| 6 | + filename: "" |
| 7 | + caption: "" |
| 8 | + focal_point: Smart |
| 9 | + preview_only: false |
| 10 | +--- |
| 11 | + |
| 12 | +# Spherical Harmonics and e3nn |
| 13 | + |
| 14 | +**Spherical Harmonics** ($Y_{\ell}^m$) are a set of orthogonal functions defined on the surface of a sphere. They are the angular portion of a set of solutions to Laplace's equation and serve as the Fourier basis for functions defined on a sphere. |
| 15 | + |
| 16 | +## 1. Mathematical Overview |
| 17 | + |
| 18 | +In spherical coordinates $(\theta, \phi)$, the real spherical harmonics are defined as: |
| 19 | +$$Y_{\ell}^m(\theta, \phi) = N_{\ell}^m P_{\ell}^m(\cos \theta) \text{trig}(m\phi)$$ |
| 20 | + |
| 21 | +Where: |
| 22 | +- $\ell \ge 0$ is the **degree** (angular momentum). |
| 23 | +- $-\ell \le m \le \ell$ is the **order**. |
| 24 | +- $P_{\ell}^m$ are the associated Legendre polynomials. |
| 25 | +- $N_{\ell}^m$ is a normalization constant. |
| 26 | + |
| 27 | +In modern geometric machine learning, we often represent these in **Cartesian coordinates** $(x, y, z)$, where they become homogeneous polynomials of degree $\ell$. |
| 28 | + |
| 29 | +--- |
| 30 | + |
| 31 | +## 2. Using the `e3nn` Library |
| 32 | + |
| 33 | +The [e3nn](https://github.com/e3nn/e3nn) library is designed for **Euclidean Neural Networks**. It uses spherical harmonics as the primary way to lift geometric data (like atomic positions) into a representation that is equivariant to rotations ($SO(3)$) and inversion ($O(3)$). |
| 34 | + |
| 35 | +### Key Concepts in e3nn: |
| 36 | +* **Irreps (Irreducible Representations):** e3nn tracks how data transforms. A spherical harmonic of degree $\ell$ belongs to the irrep $\ell$. |
| 37 | +* **Parity:** In e3nn, spherical harmonics have a definite parity $p = (-1)^\ell$. |
| 38 | +* **Coordinate Convention:** e3nn typically expects input vectors in $(x, y, z)$ but internally uses a $y, z, x$ convention for alignment with standard real spherical harmonics. |
| 39 | + |
| 40 | +--- |
| 41 | + |
| 42 | +## 3. Python Implementation |
| 43 | + |
| 44 | +To use this code, you will need to install the library: |
| 45 | +`pip install e3nn torch` |
| 46 | + |
| 47 | +### Code Example: Generating and Visualizing |
| 48 | +The following script calculates the spherical harmonic coefficients for a given set of vectors. |
| 49 | + |
| 50 | +```python |
| 51 | +import torch |
| 52 | +from e3nn import o3 |
| 53 | +import numpy as np |
| 54 | +import matplotlib.pyplot as plt |
| 55 | +from matplotlib import cm |
| 56 | + |
| 57 | +def plot_all_harmonics(l_max): |
| 58 | + fig = plt.figure(figsize=(12, 8)) |
| 59 | + |
| 60 | + # Grid coordinates for sampling the sphere |
| 61 | + phi, theta = np.mgrid[0:2*np.pi:70j, 0:np.pi:70j] |
| 62 | + x = np.sin(theta) * np.cos(phi) |
| 63 | + y = np.sin(theta) * np.sin(phi) |
| 64 | + z = np.cos(theta) |
| 65 | + vectors = torch.tensor(np.stack([x.flatten(), y.flatten(), z.flatten()], axis=1), dtype=torch.float32) |
| 66 | + |
| 67 | + plot_idx = 1 |
| 68 | + for l in range(l_max + 1): |
| 69 | + # Get irreps and compute SH for this specific L |
| 70 | + irreps = o3.Irreps.spherical_harmonics(l) |
| 71 | + sh_values = o3.spherical_harmonics(irreps, vectors, normalize=True) |
| 72 | + |
| 73 | + # There are 2L + 1 components for each L |
| 74 | + num_m = 2 * l + 1 |
| 75 | + |
| 76 | + for m_idx in range(num_m): |
| 77 | + # Create subplot: rows = l_max+1, cols = 2*l_max+1 |
| 78 | + # We center the plots by offsetting the start index |
| 79 | + ax_idx = l * (2 * l_max + 1) + (l_max - l) + m_idx + 1 |
| 80 | + ax = fig.add_subplot(l_max + 1, 2 * l_max + 1, ax_idx, projection='3d') |
| 81 | + |
| 82 | + # Extract the specific m component |
| 83 | + r_vals = sh_values[:, m_idx].reshape(70, 70).numpy() |
| 84 | + |
| 85 | + # Radial distance is absolute value, color is the sign |
| 86 | + R = np.abs(r_vals) |
| 87 | + X_p, Y_p, Z_p = R * x, R * y, R * z |
| 88 | + |
| 89 | + # Normalize colors so 0 is white/middle |
| 90 | + v_max = np.max(np.abs(r_vals)) |
| 91 | + norm = plt.Normalize(-v_max, v_max) |
| 92 | + colors = cm.RdBu(norm(r_vals)) |
| 93 | + |
| 94 | + ax.plot_surface(X_p, Y_p, Z_p, facecolors=colors, antialiased=True, shade=True) |
| 95 | + |
| 96 | + ax.set_title(f"L={l}, m_idx={m_idx}", fontsize=8) |
| 97 | + ax.axis('off') |
| 98 | + |
| 99 | + plt.tight_layout() |
| 100 | + plt.savefig('spherical_harmonics_l3.png', dpi=300, transparent=True) |
| 101 | + plt.show() |
| 102 | + |
| 103 | +plot_all_harmonics(l_max=3) |
| 104 | + |
| 105 | +``` |
| 106 | + |
| 107 | + |
| 108 | + |
| 109 | + |
0 commit comments