Density of states¶
Code: #133-000
File: apps/fermi_gas/density_of_states.ipynb Run it online:
The aim of this notebook is to help visualize the density of states for a free electron gas and how to use it to calculate the total energy.
Interface¶
The main interface (main_block_133_000) is divided two blocks: left_block_133_000 and center_block_133_000.
left_block_133_000 contains the widgets to control the figures: metal_dropdown, fermi_energy_text, fermi_temp_text, T_slider, mu_text_absolute, mu_text_relative, u_text_absolute, u_text_relative, n_text, show_trace_check and show_legend_check.
center_block_133_000 contains two bqplot figures: fig_133_001 and fig_133_002.
[1]:
from IPython.display import Image
Image(filename='../../static/images/apps/fermi_gas/133-000.png')
[1]:
The history saving thread hit an unexpected error (DatabaseError('database disk image is malformed')).History will not be written to the database.
CSS¶
A custom css file is used to improve the interface of this application. It can be found here.
[ ]:
from IPython.display import HTML
display(HTML("<head><link rel='stylesheet' type='text/css' href='./../../static/custom.css'></head>"))
display(HTML("<style>.container { width:100% !important; }</style>"))
Packages¶
[ ]:
import numpy as np
from bqplot import *
import bqplot as bq
import bqplot.marks as bqm
import bqplot.scales as bqs
import bqplot.axes as bqa
import ipywidgets as widgets
Physical functions¶
This are the functions that have a physical meaning: - get_n - get_Ef - get_mu - get_g - calculate_integrals - calculate_fd_occupancy
[ ]:
def get_n(z, dens, mass_mol):
'''
This functions calculates the electron density for a
given metal
Inputs:
z: integer for number of valence electrons
dens: float for density of metal in kg/m**3
mass_mol: float for molar mass in kg
Returns:
n: float for electron density in m**-3
'''
n = z*Na * dens/mass_mol
return n
[ ]:
def get_Ef(n):
'''
This function calculates the Fermi energy (in eV) for
a given metal with electron density n.
Inputs:
n: float for electron density in m**-3
Returns:
Ef: float for Fermi energy in eV
'''
Ef = h**2/(2*me)*(3*pi**2*n)**(2.0/3.0)
return Ef
[ ]:
def get_mu(Ef,T):
'''
This function calculates the Fermi Level (chemical potential) for
a metal characterized by Fermi energy Ef at temperature T. This
calculations is done by applying second order Sommerfeld expansion.
Inputs:
Ef: float for Fermi energy in eV
T: float for temperature in 10^4*K
Returns:
mu: float for Fermi level in eV
'''
mu = Ef*(1.0-1.0/3.0*(pi*kb*T/2.0/Ef)**2)
return mu
[ ]:
def get_g(E):
'''
This functions calculates the Density of States (DoS) for a given
energy, in the free electron gas model.
Inputs:
E: float for energy in eV
Returns:
g: number of states for unit of energy and volume (in eV**-1 A**-3)
'''
g = me/h**2/pi**2 * np.sqrt(2*me*E/h**2) * 1.0e-30
return g
[ ]:
def calculate_integrals(E_values, occupancy_values):
'''
This function calculates total energy (for unit of volume)
and total electron number (for unit of volume) by applying
numerical integration to a given energy range and occupancy.
'''
n_of_elec = 0.0
U_total = 0.0
de = (max(E_values) - min(E_values))/pts
for i in range(pts):
E = E_values[i]
occu = occupancy_values[i]
n_of_elec = n_of_elec + occu*de
U_total = U_total + E*occu*de
return n_of_elec, U_total
[ ]:
def calculate_fd_occupancy(Ef, T, mu, g_values):
'''
This function calculates the F-D distribution and occupancy
for a free electron gas for which density of states (DoS)
has been previously calculated.
Inputs:
Ef: float value for Fermi energy (in eV)
T: float value for temperatrue (in 10**4 K)
mu: float value for chemical potential (in eV)
g_values: 1darray of float values for DoS (in eV**-1 A**-3)
Returns:
tuple containing
y_values: 1darray of float values for F-D distribution
occupanvy_values: 1darray of float values for occupancy
'''
y_values = np.empty(pts)
occupancy_values = np.empty(pts)
overflow = False # Flag to control overflow with very little exponents
for i in range(pts):
if overflow == False:
E = E_values[i]
y_values[i] = 1.0/(np.exp((E-mu)/kb/T)+1.0)
if y_values[i] < 1.0e-20: # Exponents smaller than -20 considered 0
overflow = True
else:
y_values[i] = 0.0
occupancy_values[i] = y_values[i] * g_values[i]
return y_values, occupancy_values
Main interface¶
[ ]:
#######################
### PARAMETERS ###
#######################
# Universal constant (only used to get Ef and g)
h = 6.5821e-16 #Planck's reduced constant in eV*s
c = 3.0e8 # Speed of Light in m/s
me = 510998.9/c**2 # Electron mass in eV/c**2
Na = 6.0221e23
kb = 8.617e-1 # Boltzmann's in eV/(10**4 K).
pi = np.pi
# Plot parameters (temperatures in 10**4 K)
pts = 2000 # Number of points to calculate
T_min = 0.001 # Minimun T value on slider
T_max = 20.0 # Maximun T value on slider
# Metal data:(data obtained from Wikipedia)
metal_labels = ["Sodioa", "Aluminioa", "Burdina", "Kobrea"]
metal_densities = [968.0, 2700.0, 7874.0, 8960.0] # In kg/m**3
molar_masses = [0.0229, 0.026, 0.0558, 0.0635] # In Kg
valence_numbers = [1, 3, 2, 1]
# Initial values
T = 2.0 # Initial T value
metal = 1 # Initial metal index {0: 'Na', 1: 'Al', 2: 'Fe', 3: 'Cu'}
# Figures xRanges
E_values = np.linspace(0.0,50.0,pts)
[ ]:
########################
###CREATE THE FIGURES###
########################
fig_133_001 = bq.Figure(title='Fermi-Dirac banaketa',
marks=[],
axes=[],
animation_duration=0,
legend_location='top-right',
legend_style= {'fill': 'white', 'stroke': 'grey', 'width': '35%'},
legend_text= {'font-size':15},
background_style= {'fill': 'white', 'stroke': 'black'},
fig_margin=dict(top=70, bottom=60, left=80, right=30),
layout = widgets.Layout(width='50%'),
toolbar = True,
)
fig_133_002 = bq.Figure(title='Egoera-dentsitatea',
marks=[],
axes=[],
padding_y=0.0,
animation_duration=0,
legend_location='top-right',
legend_style= {'fill': 'white', 'stroke': 'grey', 'width': '35%'},
background_style= {'fill': 'white', 'stroke': 'black'},
fig_margin=dict(top=70, bottom=60, left=80, right=30),
layout = widgets.Layout(width='50%'),
toolbar = True,
)
scale_x_001 = bqs.LinearScale(min = 0.0, max = 20.0)
scale_y_001 = bqs.LinearScale(min = 0.0, max = 1.0)
scale_x_002 = bqs.LinearScale(min = 0.0, max = 20.0)
scale_y_002 = bqs.LinearScale(min = 0.0, max = 0.05, allow_padding = False)
axis_x_001 = bqa.Axis(scale=scale_x_001,
tick_format='.0f',#'0.2f',
tick_style={'font-size': '15px'},
#tick_values = np.linspace(p_min, p_max, 7),
num_ticks=3,
grid_lines = 'none',
grid_color = '#8e8e8e',
label='e (eV)',
label_location='middle',
label_style={'stroke': 'black', 'default-size': 35},
label_offset='50px')
axis_y_001 = bqa.Axis(
scale=scale_y_001,
tick_format='0.2f',
tick_style={'font-size': '15px'},
tick_values=np.linspace(0.0,1.0,5),
grid_lines = 'none',
grid_color = '#8e8e8e',
orientation='vertical',
label='f',
label_location='middle',
label_style={'stroke': 'red', 'default_size': 35},
label_offset='60px')
axis_x_002 = bqa.Axis(scale=scale_x_002,
tick_format='.0f',#'0.2f',
tick_style={'font-size': '15px'},
#tick_values = np.linspace(p_min, p_max, 7),
num_ticks=3,
grid_lines = 'none',
grid_color = '#8e8e8e',
label='e (eV)',
label_location='middle',
label_style={'stroke': 'black', 'default-size': 35},
label_offset='50px')
axis_y_002 = bqa.Axis(
scale=scale_y_002,
tick_format='.2f',#'0.2f',
tick_style={'font-size': '15px'},
tick_values = np.linspace(0.00,0.05, 6),
grid_lines = 'none',
grid_color = '#8e8e8e',
orientation='vertical',
label='g (eV**-1 A**-3)',
label_location='middle',
label_style={'stroke': 'red', 'default_size': 35},
label_offset='50px')
fig_133_001.axes = [axis_x_001, axis_y_001]
fig_133_002.axes = [axis_x_002, axis_y_002]
########################
####CREATE THE MARKS####
########################
FermiDirac_001 = bqm.Lines(
x = E_values,
y = np.empty(pts),
scales = {'x': scale_x_001, 'y': scale_y_001},
opacities = [1.0],
visible = True, #True, #t == '1.00',
colors = ['red'],
labels = ['F-D banaketa'],
display_legend = True,
)
FermiEnergy_001 = bqm.Lines(
x = np.empty(2),
y = np.linspace(0.0,1.0,2),
scales = {'x': scale_x_001, 'y': scale_y_001},
opacities = [0.6],
visible = True,
colors = ['blue'],
labels = ['Fermiren energia (Ef)'],
display_legend = True,
)
ChemicalValue_001 = bqm.Lines(
x = np.empty(2),
y = np.linspace(0.0,1.0,2),
scales = {'x': scale_x_001, 'y': scale_y_001},
opacities = [0.6],
visible = True,
colors = ['green'],
labels = ['Fermiren maila (mu)'],
display_legend = True,
)
HalfGrid_001 = bqm.Lines(
x = np.linspace(0.0,20.0,2),
y = np.full(2,0.5),
scales = {'x': scale_x_001, 'y': scale_y_001},
opacities = [0.4],
visible = True,
colors = ['#8e8e8e'],
display_legend = False,
)
FermiTrace_001 = bqm.Lines(
x = E_values,
y = [],
scales = {'x': scale_x_001, 'y': scale_y_001},
opacities = [0.2],
visible = True,
colors = ['red'],
display_legend = False,
)
DensityOfStates_002 = bqm.Lines(
x = E_values,
y = [],
scales = {'x': scale_x_002, 'y': scale_y_002},
opacities = [0.6],
visible = True,
colors = ['orange'],
labels = ['Egoera dentsitatea'],
display_legend = True,
)
Occupancy_002 = bqm.Lines(
x = E_values,
y = [],
scales = {'x': scale_x_002, 'y': scale_y_002},
opacities = [1.0],
visible = True,
colors = ['red'],
labels = ['Okupazioa'],
fill = 'bottom',
fill_opacities = [0.2],
display_legend = True,
)
FermiEnergy_002 = bqm.Lines(
x = np.empty(2),
y = np.linspace(0.0,0.05,2),
scales = {'x': scale_x_002, 'y': scale_y_002},
opacities = [0.6],
visible = True,
colors = ['blue'],
labels = ['Fermiren energia (Ef)'],
display_legend = True,
)
ChemicalValue_002 = bqm.Lines(
x = np.empty(2),
y = np.linspace(0.0,0.05,2),
scales = {'x': scale_x_002, 'y': scale_y_002},
opacities = [0.6],
visible = True,
colors = ['green'],
labels = ['Fermiren maila (mu)'],
display_legend = True,
)
fig_133_001.marks = [FermiDirac_001, FermiEnergy_001, ChemicalValue_001, HalfGrid_001, FermiTrace_001]
fig_133_002.marks = [DensityOfStates_002, Occupancy_002, FermiEnergy_002, ChemicalValue_002]
########################
###### WIDGETS #######
########################
## Input Widgets ##
T_slider = widgets.FloatSlider(
min=T_min,
max=T_max,
step=0.5,
value=T,
description='T',
disabled=False,
continuous_update=True,
orientation='horizontal',
readout=True,
readout_format='.2f',
layout = widgets.Layout(width='90%'),
)
T_slider.observe(update_temp, 'value')
metal_dropdown = widgets.Dropdown(
options=[('Sodioa', 0), ('Aluminioa', 1), ('Burdina', 2), ('Kobrea', 3)],
value=metal,
description='Gasa:',
disabled=False,
)
metal_dropdown.observe(update_metal, 'value')
show_trace_check = widgets.Checkbox(
description='Erakutsi arrastoa',
disabled=False,
value=True,
)
show_trace_check.observe(show_trace, 'value')
show_legend_check = widgets.Checkbox(
description='Erakutsi legendak',
disabled=False,
value=True,
)
show_legend_check.observe(show_legend, 'value')
## Output Widgets ##
fermi_energy_text = widgets.Label(value='')
fermi_temp_text = widgets.Label(value='')
mu_text_absolute = widgets.Label(value='')
mu_text_relative = widgets.Label(value='')
u_text_absolute = widgets.Label(value='%.2f' % 0.0)
u_text_relative = widgets.Label(value='%.2f' % 0.0)
n_text = widgets.Label(value='')
########################
### INIT FIGURES ####
########################
init_DoS(E_values)
update_metal(None) # Read widgets values and assign marks' x,y values
########################
###### LAYOUT ########
########################
left_block_133_000 = widgets.VBox([], layout=widgets.Layout(width='30%', align_self='center', align_items='center'))
left_block_133_000.children = [metal_dropdown,
widgets.HBox([widgets.Label(value='$\epsilon_F=$'),fermi_energy_text,widgets.Label(value='$eV$')]),
widgets.HBox([widgets.Label(value='$T_F=$'),fermi_temp_text,widgets.Label(value='$x10^4 K$')]),
widgets.HBox([T_slider, widgets.Label(value='$x10^4 K$')], layout=widgets.Layout(width='100%')),
widgets.HBox([widgets.Label(value='$\mu=$'),mu_text_absolute,widgets.Label(value='$eV = $'),
mu_text_relative,widgets.Label(value='$\epsilon_F$')]),
widgets.HBox([widgets.Label(value='$<U>=$'),u_text_absolute,widgets.Label(value='$eV = $'),
u_text_relative,widgets.Label(value='$\epsilon_F$')]),
widgets.HBox([widgets.Label(value='$n=$'),n_text,widgets.Label(value='$eV^{-1} \r{A}^{-3}$')]),
show_trace_check, show_legend_check
]
center_block_133_000 = widgets.HBox([], layout=widgets.Layout(width='70%', align_self='center', align_items='center'))
center_block_133_000.children = [fig_133_001, fig_133_002]
main_block_133_000 = widgets.HBox([], layout=widgets.Layout(width='100%', align_self='center', align_items='center'))
main_block_133_000.children = [left_block_133_000, center_block_133_000]
main_block_133_000