DEMO: Particle in a box#

import numpy as np
import matplotlib.pyplot as plt
import plotly
import plotly.graph_objects as go
from plotly.subplots import make_subplots
from ipywidgets.widgets import interact, interactive

%matplotlib inline
%config InlineBackend.figure_format = 'retina'

try:
    from google.colab import output
    output.enable_custom_widget_manager()
    print('All good to go')
except:
    print('Okay we are not in Colab just proceed as if nothing happened')
Okay we are not in Colab just proceed as if nothing happened
  • Set atomic units: \(h=1, m=1\)

\[\psi_n(x)=\sqrt{\frac{2}{L}}sin \frac{n\pi x}{L}\]
\[E_n = \frac{n^2 h^2}{8m L^2}\]
h, m = 1, 1 
hbar = h/(2*np.pi)

def Epib1d(n=1, L=1):
        '''Calculates energy of 1D PIB state.
        Args:
        n (int): Quantum number specifying state.
        L (float): Box dimensions in Bohr.
        Returns:
         Float energy value in Ha.
        '''

        En = (n**2 * np.pi**2 * hbar**2) / (2 * m * L**2)

        return En

    
def psi(x, n=1, L=1):      
        '''Numeric representation of the normalized 1D PIB wavefunction.
        Args:
         x  (float or array): Cartesian spatial values.
         n  (int):   Quantum number
         L  (float): Box dimensions in Bohr.
        Returns:
        Wavefunction evaulated at a point or array if input x are arrays.
        '''

        fn = np.sqrt(2/L)*np.sin(n*np.pi*x/L)

        return fn

Compute energies#

Epib1d(n=3) #-energy(n=1)
1.1250000000000002

Compare wave function and its square#

### Change these values
n=4
L=1

### Compute wavefunction and its square
x = np.linspace(0, L, 100)
psi1d = psi(x, n=n, L=L)

### Plot wave function and its square
plt.plot(x, psi1d, lw=2, label=f'$\psi_{n}(x)$')
plt.plot(x, psi1d**2, lw=2, label=f'$\psi_{n}(x)^2$')
plt.grid('--')
plt.legend()
plt.title(f'n={n}')
Text(0.5, 1.0, 'n=4')
../_images/1e0291e98c864c473f53acec140c1539c13db61b7fea0f457a65b7bf10aa385d.png

Interactive exploration of 1D quantum particle in a box#

def plot_energy_levels(L=1, max_n=1):
    
    fig, (ax, ax2) = plt.subplots(figsize=(8, 6), ncols=2)

    for n in range(1, max_n+1):
        
        En = Epib1d(n, L)
        
        ax.hlines(En, 0.5, 1.5, colors='blue', linewidth=2)
        ax.text(1.6, En, f"n={n}, E={En:.2f}", verticalalignment='center')
        
    ax.set_xlim(0, 3)
    ax.set_ylim(0, energy(max_n+1))
    ax.set_xlabel("Particle in a Box")
    ax.set_ylabel("Energy")
    ax.set_title("Energy Levels of a 1D Quantum Particle in a Box")
    ax.axes.get_xaxis().set_visible(False)
    
    x = np.linspace(0, L, 1000)
    psi1d = psi(x, n=max_n, L=L)
   
    ax2.fill(x, psi1d**2, color="green", lw=3)
    ax2.set_xlim([-0.1, L+0.1])
    ax2.set_ylim([0, 4])
    
    # Put two red lines to indicate boundaries
    ax2.axvline(0,0,10*L, color='red',lw=3)
    ax2.axvline(L,0,10*L, color='red',lw=3)
    
    # Label axis
    ax2.set_xlabel('x',fontsize=20)
    ax2.set_ylabel('$\psi_n^2(x)$',fontsize=20)
    
    #Put tiltle
    ax2.set_title('n='+str(n))
    
    plt.tight_layout()
    plt.show()
interact(plot_energy_levels, L=(0.5,2), max_n=(1,10))
<function __main__.plot_energy_levels(L=1, max_n=1)>

Particle in 3D Box#

def psi_reg(x, y, z, nx=1, ny=1, nz=1, lx=1, ly=1, lz=1):
        '''Numeric representation of the normalized 3D PIB wavefunction.
        Args:
         x, y, z (float or array): Cartesian spatial values.
         q_nx, q_ny, q_nz (int): Quantum numbers specifying state.
         lx, ly, lz (int): Box dimensions in Bohr.
        Returns:
         Wavefunction evaulated at a point or array if input x, y, z are arrays.
        '''

        return psi(x, nx, lx) * psi(y, ny, ly) * psi(z, nz, lz)


def psi_ener(nx, ny, nz, lx, ly, lz):
        '''Calculates energy of 3D PIB state.
        Args:
         qnx, qny, qnz (int): Quantum numbers specifying state.
         lx, ly, lz (float): Box dimensions in Bohr.
        Returns:
         Float energy value in Ha.
        '''

        return Epib1d(nx, lx) + Epib1d(ny, ly) + Epib1d(nz, lz)
def pib3d_plotly(nx=1, ny=1, nz=1, lx=10, ly=10, lz=10):
  '''Displays and saves isosurface of 3D PIB wavefunction.
  Args:
      nx_val, ny_val, nz_val (int): Quantum numbers specifying state.
      lx, ly, lz (int): Box dimensions in Bohr.
      psi_square (bool): Calculate prob. density (true) or wavefunction (false).
      plot_save (bool): Save a .png file of display.
  '''
  # construct 3d grid of points
  nx_p, ny_p, nz_p = 7 * lx, 7 * ly, 7 * lz
  xp, yp, zp       = np.linspace(0, lx, nx_p), np.linspace(0, ly, ny_p), np.linspace(0, lz, nz_p)
  X, Y, Z          = np.meshgrid(xp, yp, zp, indexing='ij')
  psi              = psi_reg(X, Y, Z, nx, ny, nz, lx, ly, lz)
  psi2             = psi**2
  mean_dens        = psi2.mean()

  figure = go.Figure(data=go.Isosurface(
  x=X.flatten(),
  y=Y.flatten(),
  z=Z.flatten(),
  value=psi2.flatten(), # pis or psi2
  colorscale='BlueRed',
  isomin= -mean_dens,
  isomax=  mean_dens,
  surface_count=2,
  showscale=False,
  caps=dict(x_show=False, y_show=False, z_show=False)
  ))

  figure.update_layout(scene = dict(
                  xaxis_title='x',
                  yaxis_title='y',
                  zaxis_title='z',
                  aspectmode='data'),
                  width=800,
                  height=500,
                  title_text=f'Prob. Den., isovalue = {mean_dens:.4f}')

  figure.show()
interact(pib3d_plotly, nx=(1,10), ny=(1,10), nz=(1,10), lx=(1,10), ly=(1,10), lz=(1,10))

Visualize energy levels of 3D PIB#

def plot_energy_levels(nx_max=10, ny_max=10, nz_max=10, lx=1, ly=1, lz=1):

    fig, ax = plt.subplots(figsize=(8, 6))

    for nx in range(1, nx_max+1):

        Enx = Epib1d(nx, lx)
        ax.hlines(Enx, 0.6, 1, colors='blue', linewidth=2)

    for ny in range(1, ny_max+1):

        Eny = Epib1d(ny, ly)
        ax.hlines(Eny, 1.1, 1.5, colors='green', linewidth=2)

    for nz in range(1, nz_max+1):

        Enz = Epib1d(nz, lz)
        ax.hlines(Enz, 1.6, 2.0, colors='yellow', linewidth=2)


    E_max =     Epib1d(nx_max+1, lx)+Epib1d(ny_max+1, ly)+Epib1d(nz_max+1, lz)
    ax.set_xlim(0.5, 2.1)
    ax.set_ylim(0, E_max)
    ax.set_xlabel("Particle in a 3d Box")
    ax.set_ylabel("Energy")
    ax.set_title(f"Energy Levels of a 3D Quantum Particle in a Box E={E_max:2f}")
    ax.axes.get_xaxis().set_visible(False)

    plt.tight_layout()
    plt.show()
interact(plot_energy_levels, nx=(1,10), ny=(1,10), nz=(1,10), lx=(1,10), ly=(1,10), lz=(1,10))