Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Angular Momentum

PropertyLinear MomentumAngular Momentum
Physical natureMotion along a straight lineRotation about an axis
Vector formp=mv\vec{p} = m\vec{v}L=r×p\vec{L} = \vec{r} \times \vec{p}
Effective massmmI=mr2I = m r^2
Velocityvvω=vr\omega=\frac{v}{r}
Magnitude (scalar form)p=mv\mid\vec{p}\mid = m vL=Iω\mid\vec{L}\mid = I \omega
Kinetic energyEk=p22mE_k = \dfrac{p^2}{2m}Erot=L22IE_\text{rot} = \dfrac{L^2}{2I}
Quantum operatorp^x=ix\hat{p}_x = -i\hbar\dfrac{\partial}{\partial x}L^x=y^p^zz^p^y\hat{L}_x = \hat{y}\hat{p}_z - \hat{z}\hat{p}_y
Conservation lawConserved if no net external force actsConserved if no net external torque acts
Conservation conditionFext=0\sum \vec{F}_\text{ext} = 0τext=0\sum \vec{\tau}_\text{ext} = 0

Conservation of momentum is due to symmetry

DeD0

Figure 1:Emmy Noether, a German mathematician whose first and second theorems are fundamental to mathematical physics. See more about her here.

Classical angular momentum

DeD0

Figure 2:Classical angular momentum, a vector given by the cross product of position and linear momentum. Its direction follows the right-hand rule.

L=r×p=ijkxyzpxpypz=(ypzzpy)i+(zpxxpz)j+(xpyypx)k{\vec{L} = \vec{r}\times\vec{p} = \begin{vmatrix} \vec{i} & \vec{j} & \vec{k}\\ x & y & z\\ p_x & p_y & p_z\\ \end{vmatrix}= \left(yp_z - zp_y\right)\vec{i} + \left(zp_x - xp_z\right)\vec{j} + \left(xp_y - yp_x\right)\vec{k}}

Classical picture: Rotating dumbbell

DeD0

Figure 3:Conservation of angular momentum: with no external torque, total angular momentum stays constant, so lowering the moment of inertia speeds up rotation and raising it slows rotation down.

K=m1v122+m2v222=m1r12+m2r222ω2K=\frac{m_1 v_1^2}{2}+\frac{m_2 v_2^2}{2}=\frac{m_1 r_1^2+m_2 r^2_2}{2}\omega^2
K=Iω22=L22IK=\frac{I \omega^2}{2}=\frac{L^2}{2I}
DeD0

Figure 4:Angular momentum conservation

Spherical coordinates

DeD0

Figure 5:The spherical coordinate system, defined by radial coordinate rr, azimuthal angle ϕ\phi, and polar angle θ\theta.

Laplacian

Cartesian
Polar
2=2x2+2y2+2z2\nabla^2 = \frac{{\partial^2}}{{\partial x^2}} + \frac{{\partial^2}}{{\partial y^2}} + \frac{{\partial^2}}{{\partial z^2}}

Quantum angular momentum

Cartesian
Polar
L^x=i(yzzy){\hat{L}_x = -i\hbar\left(y\frac{\partial}{\partial z} - z\frac{\partial}{\partial y}\right)}
L^y=i(zxxz){\hat{L}_y = -i\hbar\left(z\frac{\partial}{\partial x} - x\frac{\partial}{\partial z}\right)}
L^z=i(xyyx){\hat{L}_z = -i\hbar\left(x\frac{\partial}{\partial y} - y\frac{\partial}{\partial x}\right)}
L^2=Lx^2+Ly^2+Lz^2\hat{L}^2=\hat{L_x}^2+\hat{L_y}^2+\hat{L_z}^2

Components of angular momentum do not commute!

Eigenfunctions and eigenvalues of LL and LzL_z

DeD0

Figure 6:Angular momentum is quantized. Its magnitude can take specific values dictated by ll. Projections of angular momentum are also quantized and can take specific discrete values dictated by mm which can take 2l+12l+1 values never exceeding ll.

Spherical harmonics

Ylm(θ,ϕ) Y_{lm}(\theta, \phi) ExpressionColatitudinal NodesAzimuthal Nodes
Y00 Y_{00} 14π \frac{1}{\sqrt{4\pi}} 00
Y10 Y_{10} 34πcos(θ) \sqrt{\frac{3}{4\pi}} \cos(\theta) 1 (equatorial)0
Y11 Y_{1-1} 34πsin(θ)eiϕ \sqrt{\frac{3}{4\pi}} \sin(\theta) e^{-i\phi} 01
Y20 Y_{20} 516π(3cos2(θ)1) \sqrt{\frac{5}{16\pi}} (3\cos^2(\theta) - 1) 2 (colatitudinal rings)0
Y21 Y_{2-1} 154πsin(θ)cos(θ)eiϕ \sqrt{\frac{15}{4\pi}} \sin(\theta) \cos(\theta) e^{-i\phi} 1 (equatorial)1
Y22 Y_{2-2} 154πsin2(θ)e2iϕ \sqrt{\frac{15}{4\pi}} \sin^2(\theta) e^{-2i\phi} 02

Nodes of Spherical Harmonics

The nodal structure of spherical harmonics is influenced by both the degree l l and the order mm, defining the number and type of nodes as follows:

  1. Colatitudinal Nodes (Polar Nodes): The variable θ \theta defines “polar” nodes, which appear as circular bands around the sphere. The expression in cos(θ) \cos(\theta) or sin(θ) \sin(\theta) creates colatitudinal nodes:

    • For example, Y10 Y_{10} with cos(θ) \cos(\theta) has a single node at θ=π/2 \theta = \pi/2 , creating an equatorial node.

    • Y20 Y_{20} , with (3cos2(θ)1) (3\cos^2(\theta) - 1) , introduces two polar nodes, dividing the sphere into three regions along the colatitude.

  2. Azimuthal Nodes (Longitudinal Nodes): The variable ϕ \phi defines “azimuthal” nodes due to the terms eimϕe^{im\phi}, which create lines of longitude where the function changes phase. The number of azimuthal nodes is determined by m |m| :

    • If m=0 m = 0 , there are no azimuthal nodes, as seen in Y00 Y_{00} and Y10 Y_{10} .

    • For m=±1 m = \pm 1 , a single azimuthal node occurs (e.g., Y11 Y_{1-1} , Y21 Y_{2-1} ), and for m=±2 m = \pm 2 , two azimuthal nodes appear (e.g., Y22 Y_{2-2} ).

  3. Total Nodes: equal to the sum of the polar and longitudinal nodes, and exactly equal to ll. For instance, l=0l=0 has no nodes and l=4l=4 has four nodes.

Orthogonality of Spherical Harmonics

The orthogonality of spherical harmonics is expressed as:

l,ml,m=δl,lδm,m\langle l', m'| l, m \rangle = \delta_{l,l'}\delta_{m,m'}

This orthogonality condition can be explicitly written as:

0π02πYlm(θ,ϕ)Ylm(θ,ϕ)sin(θ)dθdϕ=δl,lδm,m\int_0^{\pi} \int_0^{2\pi} Y_{l'}^{m'*}(\theta, \phi) Y_l^m(\theta, \phi) \sin(\theta) \, d\theta \, d\phi = \delta_{l,l'}\delta_{m,m'}
Source
import numpy as np
from scipy.special import sph_harm_y
from scipy.integrate import dblquad

def orthogonality_test(l1, m1, l2, m2):
    """
    Computes the orthogonality integral of spherical harmonics Y(l1, m1) and Y(l2, m2).
    
    Parameters:
    l1, m1 (int): Degree and order of the first spherical harmonic.
    l2, m2 (int): Degree and order of the second spherical harmonic.
    
    Returns:
    float: The result of the orthogonality integral.
    """
    # Define the integrand for the orthogonality condition
    def integrand(theta, phi):
        Y_lm1 = sph_harm_y(l1, m1, theta, phi)
        Y_lm2 = sph_harm_y(l2, m2, theta, phi)
        return np.real(Y_lm1 * np.conj(Y_lm2)) * np.sin(theta)
    
    # Perform the integration over theta (0 to pi) and phi (0 to 2*pi)
    integral, error = dblquad(integrand, 0, 2 * np.pi, lambda _: 0, lambda _: np.pi)
    return integral

# Test orthogonality between different spherical harmonics
print("Orthogonality Tests:")
print(f"∫ Y(1,0) * Y(1,0)* = {orthogonality_test(1, 0, 1, 0):.5f} (should be close to 1)")
print(f"∫ Y(1,0) * Y(1,1)* = {orthogonality_test(1, 0, 1, 1):.5f} (should be close to 0)")
print(f"∫ Y(1,1) * Y(2,1)* = {orthogonality_test(1, 1, 2, 1):.5f} (should be close to 0)")
print(f"∫ Y(2,1) * Y(2,1)* = {orthogonality_test(2, 1, 2, 1):.5f} (should be close to 1)")
print(f"∫ Y(2,0) * Y(2,-1)* = {orthogonality_test(2, 0, 2, -1):.5f} (should be close to 0)")
Orthogonality Tests:
∫ Y(1,0) * Y(1,0)* = 1.00000 (should be close to 1)
∫ Y(1,0) * Y(1,1)* = 0.00000 (should be close to 0)
∫ Y(1,1) * Y(2,1)* = 0.00000 (should be close to 0)
∫ Y(2,1) * Y(2,1)* = 1.00000 (should be close to 1)
∫ Y(2,0) * Y(2,-1)* = -0.00000 (should be close to 0)

Plotting Spherical Harmonics

Source
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.special import sph_harm_y
from mpl_toolkits.mplot3d import Axes3D

def generate_spherical_harmonic_data(l, m):
    """
    Generates the data needed to plot the spherical harmonic for given l and m values.
    
    Parameters:
    l (int): Degree of the spherical harmonic.
    m (int): Order of the spherical harmonic.

    Returns:
    tuple: (x, y, z, fcolors_normalized) where:
        - x, y, z are the Cartesian coordinates of the spherical surface,
        - fcolors_normalized is the color data for plotting.
    """
    
    # Define theta and phi grids
    phi = np.linspace(0, np.pi, 100)          # colatitude
    theta = np.linspace(0, 2 * np.pi, 100)    # azimuth
    phi, theta = np.meshgrid(phi, theta)

    # Cartesian coordinates for the unit sphere
    x = np.sin(phi) * np.cos(theta)
    y = np.sin(phi) * np.sin(theta)
    z = np.cos(phi)

    # Calculate the spherical harmonic Y(l, m) and normalize it to [-1, 1] for color mapping
    fcolors = sph_harm_y(l, m, phi, theta).real
    fcolors_normalized = (fcolors - fcolors.min()) / (fcolors.max() - fcolors.min())
    
    return x, y, z, fcolors_normalized

l=1l=1 harmonics

Source
# Define the range of m and l values for the first three spherical harmonics
harmonics = [(0, 1), (1, 1), (-1, 1)]  # List of (m, l) pairs to plot

# Create a figure to hold three subplots in one row
fig = plt.figure(figsize=(18, 6))
fig.suptitle("First Three Spherical Harmonics", fontsize=16)

for i, (m, l) in enumerate(harmonics, start=1):

    x, y, z, fcolors_normalized = generate_spherical_harmonic_data(l, m)

    # Create a subplot for each (m, l) pair in one row
    ax = fig.add_subplot(1, 3, i, projection='3d')
    ax.plot_surface(x, y, z, rstride=1, cstride=1, facecolors=cm.seismic(fcolors_normalized), 
                    linewidth=0, antialiased=False)

    # Customize each subplot
    ax.set_title(f"$Y_{{{l},{m}}}$", fontsize=14)
    ax.set_box_aspect([1, 1, 1])  # Ensures spherical aspect ratio
    ax.set_axis_off()             # Turn off axes for clarity

# Adjust layout for a clear view of all subplots in one row
plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.show()
<Figure size 1800x600 with 3 Axes>

l=2l=2 harmonics

Source
import matplotlib.pyplot as plt
from matplotlib import cm
import numpy as np
from scipy.special import sph_harm_y
from mpl_toolkits.mplot3d import Axes3D

# Define l and the range of m values for spherical harmonics with l=2
l = 2
m_values = [-2, -1, 0, 1, 2]

# Create a figure to hold five subplots in a 2x3 layout
fig = plt.figure(figsize=(15, 10))
fig.suptitle("Spherical Harmonics with l=2", fontsize=18)

for i, m in enumerate(m_values, start=1):

    # Calculate the spherical harmonic Y(l, m) and normalize it to [-1, 1] for color mapping
    x, y, z, fcolors_normalized = generate_spherical_harmonic_data(l, m) 

    # Create a subplot for each (m, l) pair in a 2x3 grid
    ax = fig.add_subplot(2, 3, i, projection='3d')
    ax.plot_surface(x, y, z, rstride=1, cstride=1, facecolors=cm.seismic(fcolors_normalized),
                    linewidth=0, antialiased=False)

    # Customize each subplot
    ax.set_title(f"$Y_{{2,{m}}}$", fontsize=16)
    ax.set_box_aspect([1, 1, 1])  # Ensures spherical aspect ratio
    ax.set_axis_off()             # Turn off axes for clarity

# Adjust layout for a clear view of all subplots in a 2x3 grid
plt.tight_layout(rect=[0, 0, 1, 0.95])
plt.show()
<Figure size 1500x1000 with 5 Axes>

Total number of nodes = ll

Source
import plotly.io as pio
pio.renderers.default = "plotly_mimetype"   # interactive in Jupyter-Book
import numpy as np
import plotly.graph_objects as go
from scipy.special import sph_harm_y

# Define the range of m and l values for the first three spherical harmonics
harmonics = [(1, 1), (1, 2), (2, 3)]  # List of (m, l) pairs to plot

# Initialize the figure
fig = go.Figure()


# Loop over each harmonic and create a separate subplot
for i, (m, l) in enumerate(harmonics, start=1):
    
    # Calculate the spherical harmonic Y(l, m) and normalize it to [0, 1]
    x, y, z, fcolors_normalized = generate_spherical_harmonic_data(l, m) 
    
    # Add the spherical harmonic to the figure as a surface in a new scene
    fig.add_trace(go.Surface(
        x=x, y=y, z=z,
        surfacecolor=fcolors_normalized,
        colorscale='rdbu',
        showscale=False,
        name=f"Y_{{{l},{m}}}",
        scene=f'scene{i}'  # Assign each plot to a different scene
    ))

# Update layout to arrange scenes in a row and add titles as annotations
fig.update_layout(
    title="Three Spherical Harmonics: m=1, l=1, 2, 3",
    scene=dict(domain=dict(x=[0, 0.33]), xaxis=dict(visible=False), yaxis=dict(visible=False), zaxis=dict(visible=False), aspectmode='cube'),
    scene2=dict(domain=dict(x=[0.33, 0.66]), xaxis=dict(visible=False), yaxis=dict(visible=False), zaxis=dict(visible=False), aspectmode='cube'),
    scene3=dict(domain=dict(x=[0.66, 1]), xaxis=dict(visible=False), yaxis=dict(visible=False), zaxis=dict(visible=False), aspectmode='cube'),
    annotations=[
        dict(text="Y_{2,0}", x=0.16, y=1.05, showarrow=False, xref="paper", yref="paper", font=dict(size=14)),
        dict(text="Y_{2,1}", x=0.5, y=1.05, showarrow=False, xref="paper", yref="paper", font=dict(size=14)),
        dict(text="Y_{2,-1}", x=0.83, y=1.05, showarrow=False, xref="paper", yref="paper", font=dict(size=14))
    ]
)

# Display the figure
fig.show()
Loading...

Alternative visualizations of Spherical Harmonics

Source
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from scipy.special import sph_harm_y

# Set up the subplots with two side-by-side 3D plots
fig = make_subplots(rows=1, cols=2, specs=[[{'is_3d': True}, {'is_3d': True}]])

# Define theta and phi grids for spherical coordinates
theta = np.linspace(0, np.pi, 100)
phi = np.linspace(0, 2 * np.pi, 100)
theta, phi = np.meshgrid(theta, phi)

# Convert spherical to Cartesian coordinates for the surface plots
x = np.sin(theta) * np.cos(phi)
y = np.sin(theta) * np.sin(phi)
z = np.cos(theta)

# Compute the spherical harmonic Y_{1,-1}
m, l = -1, 1
r0a = np.sqrt(3 / (4 * np.pi)) * y  # Y_{1,-1} harmonic on y-axis
r0 = np.abs(r0a)  # Absolute value for magnitude scaling

# First plot: Scaled by the spherical harmonic (bead-like structure)
fig.add_trace(
    go.Surface(
        x=r0 * x, y=r0 * y, z=r0 * z,  # Scale coordinates by |Y_{1,-1}|
        surfacecolor=r0a,  # Color by Y_{1,-1} values
        colorscale='RdBu'
    ),
    row=1, col=1
)

# Second plot: Standard unit sphere with grayscale color
fig.add_trace(
    go.Surface(
        x=x, y=y, z=z,  # Unit sphere without scaling
        surfacecolor=z,  # Color by z-coordinate for simplicity
        colorscale='RdBu'
    ),
    row=1, col=2
)

# Update layout for both plots
fig.update_layout(
    font_family="JuliaMono",
    showlegend=False,
    margin=dict(l=0, r=0, b=0, t=0),
    paper_bgcolor='rgba(0,0,0,0)',
)

# Set scene properties with adjusted axis limits for each plot
fig.update_scenes(
    dict(
        xaxis=dict(nticks=4, range=[-0.5, 0.5]),  # Limit range to reduce empty space
        yaxis=dict(nticks=4, range=[-0.5, 0.5]),
        zaxis=dict(nticks=4, range=[-0.5, 0.5]),
        aspectratio=dict(x=1, y=1, z=1)
    ),
    row=1, col=1
)
fig.update_scenes(
    dict(
        xaxis=dict(nticks=4, range=[-1.8, 1.8]),
        yaxis=dict(nticks=4, range=[-1.8, 1.8]),
        zaxis=dict(nticks=4, range=[-1.8, 1.8]),
        aspectratio=dict(x=1, y=1, z=1)
    ),
    row=1, col=2
)

# Hide color scales for a cleaner look
fig.update_traces(showscale=False)

# Show the plot
fig.show()
Loading...
Source
import numpy as np
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from matplotlib import cm
import matplotlib
import matplotlib.pyplot as plt

# Define theta (angle) values
theta = np.linspace(0, 2 * np.pi, 100)

# Compute spherical harmonic values (scaled sin(theta) for two-lobe structure)
Y_1m1_values = np.sin(theta)  # Y_{1,-1} varies with sin(theta) for the two-lobe shape
r_values = np.abs(Y_1m1_values)  # Radial scaling based on |Y_{1,-1}|

# Set up the color map
cmap = matplotlib.colormaps["RdBu"]
norm = plt.Normalize(vmin=-1, vmax=1)

# Create subplots for two polar plots
fig = make_subplots(rows=1, cols=2, specs=[[{'type': 'polar'}, {'type': 'polar'}]])

# First polar plot: Two-lobed structure with color gradient
for i in range(len(theta) - 1):
    fig.add_trace(
        go.Scatterpolar(
            r=[r_values[i], r_values[i + 1]],
            theta=[np.degrees(theta[i]), np.degrees(theta[i + 1])],
            mode="lines",
            line=dict(color=matplotlib.colors.to_hex(cmap(norm(Y_1m1_values[i]))), width=5),
            showlegend=False
        ),
        row=1, col=1
    )

# Second polar plot: Unit circle with consistent color gradient
for i in range(len(theta) - 1):
    fig.add_trace(
        go.Scatterpolar(
            r=[1, 1],  # Fixed radius for unit circle
            theta=[np.degrees(theta[i]), np.degrees(theta[i + 1])],
            mode="lines",
            line=dict(color=matplotlib.colors.to_hex(cmap(norm(Y_1m1_values[i]))), width=5),
            showlegend=False
        ),
        row=1, col=2
    )

# Update layout for both polar plots with fixed radius range and equal appearance
fig.update_layout(
    font_family="JuliaMono",
    showlegend=False,
    margin=dict(l=0, r=0, b=0, t=0),
    polar=dict(radialaxis=dict(range=[0, 1.2])),  # First plot axis range
    polar2=dict(radialaxis=dict(range=[0, 1.2]))  # Second plot axis range
)

# Show the plot
fig.show()
Loading...

Learn More about Spherical Harmonics