8  Ü1 · QM Grundlagen

Wellenfunktionen, Operatoren und die Schrödinger-Gleichung

Autor:in

ZHAW Institut für Data Science

8.1 Lernziele

Nach dieser Übung kannst du:

  • Wellenfunktionen für einfache Systeme (Teilchen im Kasten) numerisch berechnen und visualisieren
  • Erwartungswerte von Observablen (Ort, Impuls, Energie) berechnen
  • Die Heisenbergsche Unschärferelation numerisch überprüfen
  • Eine erste Hartree-Fock-Rechnung mit PySCF ausführen und die Ausgabe interpretieren
import numpy as np
import matplotlib.pyplot as plt
from scipy.linalg import eigh

# Einheitliches Plot-Styling
plt.rcParams.update({'figure.dpi': 120, 'font.size': 11})

8.2 Aufgabe 1 · Teilchen im Kasten (Partikel-in-einer-Box)

Das eindimensionale Teilchen-im-Kasten-Modell (Länge \(L\), unendlich hohe Wände) hat exakte analytische Lösungen:

\[\psi_n(x) = \sqrt{\frac{2}{L}} \sin\!\left(\frac{n\pi x}{L}\right), \quad E_n = \frac{n^2 \pi^2 \hbar^2}{2mL^2}\]

8.2.1 1a) Wellenfunktionen visualisieren

# Parameter (atomare Einheiten: hbar = m_e = 1)
L = 10.0          # Kastenlänge in Bohr
N_grid = 500      # Gitterpunkte
x = np.linspace(0, L, N_grid)

def psi_box(n, x, L):
    """Wellenfunktion des Teilchens im Kasten für Quantenzahl n."""
    return np.sqrt(2 / L) * np.sin(n * np.pi * x / L)

def E_box(n, L):
    """Energie in atomaren Einheiten (hbar=m=1)."""
    return (n * np.pi)**2 / (2 * L**2)

# Plotte n = 1, 2, 3, 4
fig, axes = plt.subplots(2, 2, figsize=(10, 7))
axes = axes.ravel()

for i, n in enumerate([1, 2, 3, 4]):
    psi = psi_box(n, x, L)
    prob = psi**2
    En = E_box(n, L)
    
    axes[i].plot(x, psi, label=r'$\psi_n$', color='steelblue', lw=2)
    axes[i].plot(x, prob, label=r'$|\psi_n|^2$', color='darkorange', lw=2, ls='--')
    axes[i].set_title(f'n = {n},  E = {En:.4f} Hartree')
    axes[i].set_xlabel('x / Bohr')
    axes[i].legend(fontsize=9)
    axes[i].axhline(0, color='k', lw=0.5)

plt.suptitle('Wellenfunktionen und Wahrscheinlichkeitsdichten: Teilchen im Kasten', fontsize=13)
plt.tight_layout()
plt.show()

8.2.2 1b) Normierung überprüfen

Aufgabe: Überprüfe numerisch, dass \(\langle\psi_n|\psi_n\rangle = 1\) für \(n = 1, 2, 3\). Berechne ausserdem \(\langle\psi_1|\psi_2\rangle\) und interpretiere das Ergebnis.

dx = x[1] - x[0]  # Gitterabstand

print("Normierungsprüfung (numerische Integration):")
for n in [1, 2, 3]:
    psi = psi_box(n, x, L)
    norm = np.trapezoid(psi**2, x)
    print(f"  <psi_{n}|psi_{n}> = {norm:.8f}")

print()
print("Orthogonalität:")
for (m, n) in [(1, 2), (1, 3), (2, 3)]:
    overlap = np.trapezoid(psi_box(m, x, L) * psi_box(n, x, L), x)
    print(f"  <psi_{m}|psi_{n}> = {overlap:.2e}")
Normierungsprüfung (numerische Integration):
  <psi_1|psi_1> = 1.00000000
  <psi_2|psi_2> = 1.00000000
  <psi_3|psi_3> = 1.00000000

Orthogonalität:
  <psi_1|psi_2> = 0.00e+00
  <psi_1|psi_3> = 5.55e-17
  <psi_2|psi_3> = -5.55e-17

8.2.3 1c) Erwartungswerte

Aufgabe: Berechne \(\langle x \rangle\), \(\langle x^2 \rangle\) und \(\sigma_x = \sqrt{\langle x^2\rangle - \langle x\rangle^2}\) für \(n = 1, 2, 3\).

print(f"{'n':>3} | {'<x>':>10} | {'<x²>':>10} | {'σ_x':>10}")
print("-" * 42)

for n in [1, 2, 3, 4]:
    psi = psi_box(n, x, L)
    prob = psi**2
    
    x_mean  = np.trapezoid(prob * x, x)
    x2_mean = np.trapezoid(prob * x**2, x)
    sigma_x = np.sqrt(x2_mean - x_mean**2)
    
    print(f"{n:>3} | {x_mean:>10.4f} | {x2_mean:>10.4f} | {sigma_x:>10.4f}")

print()
print(f"Analytisch: <x> = L/2 = {L/2:.4f}")
  n |        <x> |       <x²> |        σ_x
------------------------------------------
  1 |     5.0000 |    28.2673 |     1.8076
  2 |     5.0000 |    32.0668 |     2.6583
  3 |     5.0000 |    32.7704 |     2.7876
  4 |     5.0000 |    33.0167 |     2.8314

Analytisch: <x> = L/2 = 5.0000

8.3 Aufgabe 2 · Numerische Lösung der Schrödinger-Gleichung

Löse die zeitunabhängige Schrödinger-Gleichung für ein harmonisches Potential \(V(x) = \frac{1}{2}kx^2\) numerisch via Finite-Differenzen-Diskretisierung.

Der diskrete kinetische Energie-Operator lautet: \[T_{ij} = -\frac{\hbar^2}{2m}\cdot\frac{-2\delta_{ij} + \delta_{i,j-1} + \delta_{i,j+1}}{(\Delta x)^2}\]

def solve_schrodinger_1d(V_func, x_min=-8, x_max=8, N=600, n_states=6):
    """
    Löst die 1D stationäre Schrödinger-Gleichung via Finite Differenzen.
    Atomare Einheiten: hbar = m = 1.
    
    Returns: x, energies (n_states lowest), wavefunctions (columns)
    """
    x = np.linspace(x_min, x_max, N)
    dx = x[1] - x[0]
    
    # Kinetische Energie: Tridiagonal-Matrix
    diag     = np.ones(N) / dx**2           # Hauptdiagonale
    off_diag = -0.5 * np.ones(N-1) / dx**2 # Nebendiagonalen
    T = np.diag(diag) + np.diag(off_diag, 1) + np.diag(off_diag, -1)
    
    # Potentialmatrix (diagonal)
    V = np.diag(V_func(x))
    
    # Hamilton-Operator H = T + V
    H = T + V
    
    # Eigenwertproblem lösen (symmetrisch)
    energies, psi = eigh(H, subset_by_index=[0, n_states - 1])
    
    # Normieren
    for i in range(n_states):
        psi[:, i] /= np.sqrt(np.trapezoid(psi[:, i]**2, x))
    
    return x, energies, psi


# Harmonisches Potential (k=1, analytische Lösung: E_n = n + 1/2)
k = 1.0
x, E, psi = solve_schrodinger_1d(lambda x: 0.5 * k * x**2)

print("Harmonischer Oszillator – Energievergleich:")
print(f"{'n':>3} | {'E_num':>10} | {'E_exakt':>10} | {'Fehler':>10}")
print("-" * 42)
for n in range(6):
    E_exact = n + 0.5  # in atomaren Einheiten
    print(f"{n:>3} | {E[n]:>10.6f} | {E_exact:>10.6f} | {abs(E[n]-E_exact):>10.2e}")
Harmonischer Oszillator – Energievergleich:
  n |      E_num |    E_exakt |     Fehler
------------------------------------------
  0 |   0.499978 |   0.500000 |   2.23e-05
  1 |   1.499889 |   1.500000 |   1.11e-04
  2 |   2.499710 |   2.500000 |   2.90e-04
  3 |   3.499442 |   3.500000 |   5.58e-04
  4 |   4.499086 |   4.500000 |   9.14e-04
  5 |   5.498640 |   5.500000 |   1.36e-03
# Visualisierung
fig, ax = plt.subplots(figsize=(9, 6))

colors = plt.cm.viridis(np.linspace(0.1, 0.9, 6))
V_plot = 0.5 * k * x**2
ax.plot(x, V_plot, 'k-', lw=2, label='$V(x) = \\frac{1}{2}x^2$')

for n in range(5):
    scale = 0.8  # Skalierung für Darstellung
    ax.axhline(E[n], color=colors[n], ls=':', lw=1, alpha=0.5)
    ax.plot(x, scale * psi[:, n] + E[n], color=colors[n], lw=2,
            label=f'n={n}, E={E[n]:.3f}')

ax.set_xlim(-6, 6)
ax.set_ylim(-0.3, 5.5)
ax.set_xlabel('x / Bohr')
ax.set_ylabel('Energie / Hartree')
ax.set_title('Harmonischer Oszillator: numerische Eigenzustände')
ax.legend(fontsize=9, loc='upper center')
plt.tight_layout()
plt.show()


8.4 Aufgabe 3 · Heisenbergsche Unschärferelation

Die Heisenbergsche Unschärferelation lautet: \(\sigma_x \cdot \sigma_p \geq \frac{\hbar}{2}\)

Der Impuls-Operator in Ortsdarstellung ist \(\hat{p} = -i\hbar\,\frac{d}{dx}\), dessen Erwartungswert via numerische Ableitung berechnet wird.

Aufgabe: Überprüfe die Unschärferelation für die ersten 4 Zustände des harmonischen Oszillators. Der Grundzustand des harmonischen Oszillators erfüllt die Gleichung exakt – überprüfe das!

dx = x[1] - x[0]

print("Heisenbergsche Unschärferelation (hbar = 1):")
print(f"{'n':>3} | {'σ_x':>8} | {'σ_p':>8} | {'σ_x·σ_p':>10} | {'≥ 0.5?':>8}")
print("-" * 50)

for n in range(4):
    p = psi[:, n]
    prob = p**2
    
    # Ortsunschärfe
    x_mean  = np.trapezoid(prob * x, x)
    x2_mean = np.trapezoid(prob * x**2, x)
    sigma_x = np.sqrt(x2_mean - x_mean**2)
    
    # Impulsunschärfe: numerische Ableitung (finite Differenz)
    dpsi = np.gradient(p, dx)          # d/dx psi
    d2psi = np.gradient(dpsi, dx)      # d²/dx² psi
    
    # <p²> = integral psi* (-d²/dx²) psi dx  (atomare Einheiten)
    p2_mean = -np.trapezoid(p * d2psi, x)
    # <p>   = integral psi* (-i d/dx) psi dx -> imaginär, für Reelfkt. = 0
    p_mean  = 0.0  # Reelle Eigenfunktionen: <p> = 0
    sigma_p = np.sqrt(max(p2_mean - p_mean**2, 0))
    
    product = sigma_x * sigma_p
    ok = "✓" if product >= 0.499 else "✗"
    
    print(f"{n:>3} | {sigma_x:>8.4f} | {sigma_p:>8.4f} | {product:>10.4f} | {ok:>8}")

print()
print("Analytisch (harm. Osz.): σ_x·σ_p = (n + 1/2)·ℏ")
for n in range(4):
    print(f"  n={n}: {n + 0.5:.1f}")
Heisenbergsche Unschärferelation (hbar = 1):
  n |      σ_x |      σ_p |    σ_x·σ_p |   ≥ 0.5?
--------------------------------------------------
  0 |   0.7071 |   0.7070 |     0.4999 |        ✓
  1 |   1.2247 |   1.2245 |     1.4996 |        ✓
  2 |   1.5810 |   1.5806 |     2.4988 |        ✓
  3 |   1.8705 |   1.8699 |     3.4978 |        ✓

Analytisch (harm. Osz.): σ_x·σ_p = (n + 1/2)·ℏ
  n=0: 0.5
  n=1: 1.5
  n=2: 2.5
  n=3: 3.5

8.5 Aufgabe 4 · Erste PySCF-Rechnung: H₂O

Führe eine Hartree-Fock-Rechnung für H₂O durch und interpretiere die Ausgabe.

Voraussetzung: pyscf muss installiert sein (uv run pip install pyscf im Projektverzeichnis).

try:
    from pyscf import gto, scf
    PYSCF_AVAILABLE = True
except ImportError:
    PYSCF_AVAILABLE = False
    print("PySCF nicht gefunden. Installiere mit: uv add pyscf")

if PYSCF_AVAILABLE:
    # Molekül definieren (experimentelle Geometrie, Angström)
    mol = gto.Mole()
    mol.atom = """
        O   0.000  0.000  0.000
        H   0.757  0.586  0.000
        H  -0.757  0.586  0.000
    """
    mol.basis = 'sto-3g'
    mol.verbose = 3
    mol.build()

    # RHF-Rechnung
    mf = scf.RHF(mol)
    E_hf = mf.kernel()
converged SCF energy = -74.9629466565388
if PYSCF_AVAILABLE:
    import pandas as pd
    
    mo_energies = mf.mo_energy  # in Hartree
    mo_occ      = mf.mo_occ
    
    df = pd.DataFrame({
        'MO':        range(1, len(mo_energies) + 1),
        'E [Hartree]': mo_energies,
        'E [eV]':    mo_energies * 27.211,
        'Besetzt':   mo_occ.astype(int)
    })
    
    print(f"\nHF-Energie (STO-3G): {E_hf:.6f} Hartree")
    print(f"HOMO-Energie:         {mo_energies[mo_occ > 0][-1]*27.211:.2f} eV")
    print(f"LUMO-Energie:         {mo_energies[mo_occ == 0][0]*27.211:.2f} eV")
    print(f"HOMO-LUMO-Gap:        {(mo_energies[mo_occ == 0][0] - mo_energies[mo_occ > 0][-1])*27.211:.2f} eV")
    print()
    print(df.to_string(index=False))

HF-Energie (STO-3G): -74.962947 Hartree
HOMO-Energie:         -10.65 eV
LUMO-Energie:         16.48 eV
HOMO-LUMO-Gap:        27.12 eV

 MO  E [Hartree]      E [eV]  Besetzt
  1   -20.241762 -550.798579        2
  2    -1.268360  -34.513356        2
  3    -0.617863  -16.812664        2
  4    -0.452999  -12.326557        2
  5    -0.391242  -10.646096        2
  6     0.605576   16.478334        0
  7     0.742245   20.197237        0

8.5.1 Reflexionsfragen

  1. Warum sind alle MO-Energien für besetzte Orbitale negativ? Was bedeutet das physikalisch?
  2. Das HOMO von H₂O liegt bei ca. −12.6 eV (experimentell: erstes Ionisierungspotential). Wie gut ist STO-3G?
  3. Wieso spricht man beim Koopmans-Theorem von einer Näherung? Was wird vernachlässigt?

8.6 Zusammenfassung

In dieser Übung hast du:

  • Wellenfunktionen für das Teilchen im Kasten und den harmonischen Oszillator berechnet und visualisiert
  • Erwartungswerte numerisch via numerischer Integration bestimmt
  • Die Heisenbergsche Unschärferelation am Beispiel des harmonischen Oszillators überprüft
  • Eine erste HF/STO-3G-Rechnung mit PySCF für H₂O durchgeführt