"""
"""
#! /usr/bin/python
# -*- coding: utf-8 -*-
doc = """
# Simple Harmonic Oscillator (SHO)
# English :
# interest of this program : numerical experiment of schrodinger equation
# static solution of Harmonic Oscillator
# e > v : sinus
# e < v : exponential decreasing first but finally diverging.
# we can detect the energy of transition
# between positive and negative divergence.
# Français :
# résolution numérique de l'équation de Schroedinger
# recherche des états propres (e, phi)
# Solution indépendante du temps de l'oscillateur harmonique
# La partie e > v : oscille
# La partie e < v : décroît exponentiellement mais finit toujours par diverger
# l'énergie propre est comprise entre 2 énergies voisines qui divergent en sens contraires
"""
import math
import matplotlib.pyplot
def data( ) :
# usage : (k, f0, df0, dx, xmin, xmax, ymin, ymax) = data()
# point de départ de l'intégration numérique
k = 1 # potentiel : v = k x²
# solution paire : f0 > 0 et df0 = df0/dx = 0
f0 = 1
df0 = 0
dx = 0.01 # pas d'espace
# bornes du graphique
(xmin, xmax, ymin, ymax) = (0, 5, -3, 3)
return (k, f0, df0, dx, xmin, xmax, ymin, ymax)
def normalization_real(phi) :
# normalisation de la fonction phi (sous forme de tableau)
n = len(phi)
phi_integral = 0
for i in range(n) :
phi_integral += phi[i] * phi[i]
phi_integral = math.sqrt(phi_integral)
for i in range(n) :
phi[i] /= phi_integral
phi[i] /= phi_integral
return
def schroedinger_step(x0, fx0, dfx0, k, e, dx) :
"""
# intégration d'un pas d'espace de l'équation de Schroedinger
# i hbar part f / part t = - i hbar part^2 f / part x^2 + (V - E) f
# on pose toutes les constantes = 1
# on résoud : f''(x) = (V - E) f(x)
# avec V(x) = k x^2
# schéma numérique à "vitesse" décalée
# comme : f''(x) = [ f'(x+dx) - f'(x) ] / dx
# f'(x+dx/2) = f'(x) + (dx/2) f''(x)
# comme : f'(x+dx/2) = [ f(x+dx) - f(x) ] / dx
# f(x+dx) = f(x) + dx f'(x+dx/2)
"""
# print("x0, fx0, dfx0, k, e, dx =", (x0, fx0, dfx0, k, e, dx) )
x1 = x0 + dx
vx = k * x0**2
d2fx0 = (vx - e) * fx0
dfx1 = dfx0 + dx * d2fx0
fx1 = fx0 + dx * 0.5 * (dfx0 + dfx1)
return (x1, fx1, dfx1)
def plot_phi(x, phi, divergence, e) :
# displays phi(x)
matplotlib.pyplot.plot(x, phi)
if divergence > 0 :
matplotlib.pyplot.text(x[-2], phi[-2]-0.2, f"${e}$")
else :
matplotlib.pyplot.text(x[-2], phi[-2]-0.2, f"${e}$")
return
def plot_potential( x, k ) :
n = len(x)
v = [ None for i in range(n) ]
for i in range(n) :
v[i] = k * x[i]**2
matplotlib.pyplot.plot(x, v, color="black")
matplotlib.pyplot.text(1, 2.5, r"$V=kx^2$")
return
def schroedinger_real(e, n) :
"""
# la fonction phi(x) finit toujours par diverger
# quand elle est presque nulle, très en dessous du potentiel
# (exponentielle divergente)
"""
# state at x=0
(k, f0, df0, dx, xmin, xmax, ymin, ymax) = data()
x0 = 0
divergence = 0
# print("énergie testée : e=", e)
(x, phi, dphi) = ([0], [f0], [df0])
for i in range(n) :
(x1, f1, df1) = schroedinger_step(x0, f0, df0, k, e, dx)
# storage of i+1 for next schroedinger_step
x.append( x1 )
phi.append( f1 )
dphi.append( df1 )
# bascule :
(x0, f0, df0) = (x1, f1, df1)
if abs(f1) > ymax :
print(f" e = {e} : divergence de phi pour x={x1}")
if f1 > 0 : divergence = 1
else : divergence = -1 # fx1 < 0
break # for i
return (x, phi, dphi, divergence)
def schroedinger_dichotomie( ):
"""
# Dans l'équation de Schroedinger pour l'oscillateur harmonique,
# on teste différentes énergies de l'intervalle [e_min, e_max] :
# la fonction phi diverge plus ou moins vite
# Pour encadrer la valeur propre, il faut des divergences de sens opposées
"""
# state at x=0
(k, f0, df0, dx, xmin, xmax, ymin, ymax) = data()
n = int(xmax / dx)
print("nombre de pas d'intégration : n=", n)
# static schroedinger :
matplotlib.pyplot.title("Harmonic Oscillator")
matplotlib.pyplot.text(2, 1.1*f0, r"$E$")
matplotlib.pyplot.text(2, 0.3*f0, r"$\phi_E(x)$")
matplotlib.pyplot.axhline(0, 0, 4.5, color="black")
divergence = 0
e_min = 0.95
e_max = 1.05
print("# Test des énergies dans l'intervalle [", e_min, ",", e_max, "]")
(x, phi, dphi, divergence_min) = schroedinger_real(e_min, n)
plot_phi(x, phi, divergence_min, e_min)
(x, phi, dphi, divergence_max) = schroedinger_real(e_max, n)
plot_phi(x, phi, divergence_max, e_max)
if divergence_min * divergence_max >= 0 :
print(" Mauvais encadrement : mêmes divergences")
print(f" e_min = {e_min} ; e_max = {e_max}")
return
e0 = e_min
for j in range(10) :
e = (e_min + e_max) / 2
divergence_precedente = divergence
(x, phi, dphi, divergence) = schroedinger_real(e, n)
plot_phi(x, phi, divergence, e)
# tracé de l'énergie (droite horizontale ) comparer au potentiel
matplotlib.pyplot.plot( [x[0], x[len(x)-1]], [e, e] )
if divergence == divergence_min :
e_min = e
elif divergence == divergence_max :
e_max = e
else : # divergence = 0
print(f" e = {e} : pas de divergence avant xmax={xmax}")
break
print(f" l'énergie e est dans [ {e_min}, {e_max} ]")
plot_potential( x, k )
# normalization_real(phi)
matplotlib.pyplot.axis( [xmin, xmax, ymin, ymax] )
matplotlib.pyplot.show( )
return
schroedinger_dichotomie( )
"""
"""