|
17 | 17 | "\n",
|
18 | 18 | "**Source code:** https://github.com/osscar-org/quantum-mechanics/blob/master/notebook/band-theory/free_electron.ipynb\n",
|
19 | 19 | "\n",
|
20 |
| - " The main objective of this notebook is to demonstrate the bandstructure for the\n", |
21 |
| - " free-electron model in a periodic lattice.\n", |
| 20 | + " The main objective of this notebook is to demonstrate the electronic bandstructure within the free-electron model for a periodic crystalline lattice of a metal.\n", |
| 21 | + " \n", |
| 22 | + " \n", |
| 23 | + "Throughout the notebook, we employ the empty lattice (free-electron) approximation for the electrons in a periodic \n", |
| 24 | + "solid system. Using it, we compute and plot the electronic band structure for three \n", |
| 25 | + "types of Bravais lattice: simple cubic (SC), face-centered cubic (FCC) and body-centered cubic (BCC). We get the path in reciprocal space for the band structure \n", |
| 26 | + "from the <a href=\"https://seekpath.readthedocs.io/en/latest/index.html\">seekpath</a>\n", |
| 27 | + "package.\n", |
22 | 28 | "\n",
|
23 | 29 | "<hr style=\"height:1px;border:none;color:#cccccc;background-color:#cccccc;\" />"
|
24 | 30 | ]
|
|
29 | 35 | "source": [
|
30 | 36 | "## **Goals**\n",
|
31 | 37 | "\n",
|
32 |
| - "* Familiarize oneself with the free-electron model.\n", |
33 |
| - "* Examine the electronic band structure of the free electron model for different crystal structures.\n" |
| 38 | + "* Familiarize yourself with the free-electron model of a metallic solid.\n", |
| 39 | + "* Examine the electronic band structure of the free-electron model for different crystalline structures.\n" |
34 | 40 | ]
|
35 | 41 | },
|
36 | 42 | {
|
|
52 | 58 | " <li> Can you describe the shape of the band structure in the 1st Brillouin zone?\n",
|
53 | 59 | " <details>\n",
|
54 | 60 | " <summary style=\"color: red\">Solution</summary>\n",
|
55 |
| - " In the free electron model, the dispersion relation between electronic energy and wavevector is given by $E=\\frac{\\hbar^2k^2}{2m}$. Consequently, the shape of the bands is parabolic. \n", |
| 61 | + " In the free electron model, the dispersion relation between electronic energy and wavevector is given by $E=\\frac{\\hbar^2k^2}{2m}$. Accordingly, the shape of the bands is parabolic. \n", |
56 | 62 | " </details> \n",
|
57 | 63 | " </li>\n",
|
58 |
| - " <li> What properties of a material shall be best captured by the free electron model?\n", |
| 64 | + " <li> What properties of a material shall be best captured by the free-electron model?\n", |
59 | 65 | " <details>\n",
|
60 | 66 | " <summary style=\"color: red\">Solution</summary>\n",
|
61 | 67 | " As the free-electron model neglects the effect of the ionic potential on the electrons, material properties which are primarily dependent on the kinetic energy of the conduction electrons are those which shall be best described by the model.\n",
|
62 | 68 | " </details> \n",
|
63 | 69 | " </li>\n",
|
64 |
| - " <li> Look at the bandstructure plots for different crystal structures by toggling the \"Cell type\" radio buttons. Why is the bandstructure associated with the BCC crystal structure much denser than that of the simple cubic cell (i.e., why is there so many more bands in the energy range considered for BCC compared to SC).\n", |
| 70 | + " <li> Consider the simple cubic lattice, and consider the lowest energy band from Γ to the X point, from Γ to the R point, and from Γ to the M point. The curvature of those bands seem to be the same. Is this to be expected? What about the Γ-L, Γ-X, and Γ-K in the FCC case? Or the Γ-H, Γ-N, and Γ-P in the BCC case?\n", |
65 | 71 | " <details>\n",
|
66 | 72 | " <summary style=\"color: red\">Solution</summary>\n",
|
67 |
| - " Recalling that the energy eigenvalues are given by $\\large E = \\frac{\\hbar^2(\\vec{k}+\\vec{G})^2}{2m}$, we can see that the origin of the increased density of bands for BCC is due to its Brillouin zone giving rise to a larger number of G-vectors with small magnitudes. This in turn increases the number of low-lying energy bands.\n", |
| 73 | + " For a free electron case, the bands are isotropic (i.e., they are the same, independent of the direction in k space), and the effective mass is just the free-electron mass: $m^*=m_0$. Therefore, we expect all curvatures (of the lowest energy band starting from Γ) to be the same.\n", |
68 | 74 | " </details> \n",
|
69 | 75 | " </li>\n",
|
70 | 76 | "</ol>\n",
|
|
81 | 87 | "import numpy as np\n",
|
82 | 88 | "import seekpath\n",
|
83 | 89 | "import re\n",
|
84 |
| - "import matplotlib\n", |
85 |
| - "from ase.dft.dos import linear_tetrahedron_integration as lti\n", |
86 |
| - "from ase.dft.kpoints import monkhorst_pack\n", |
87 |
| - "from ase.cell import Cell\n", |
88 |
| - "from scipy.stats import multivariate_normal\n", |
89 | 90 | "from widget_bzvisualizer import BZVisualizer"
|
90 | 91 | ]
|
91 | 92 | },
|
|
166 | 167 | "metadata": {},
|
167 | 168 | "outputs": [],
|
168 | 169 | "source": [
|
169 |
| - "def get_bands(real_lattice_bohr, reference_distance = 0.025, g_vectors_range = 3):\n", |
170 |
| - "\n", |
| 170 | + "def get_bands(real_lattice_bohr, reference_distance = 0.05, g_vectors_range = 3):\n", |
| 171 | + " \"\"\"Function to return the band structure of a free-electron model.\n", |
| 172 | + " \n", |
| 173 | + " :param real_lattice_bohr: 3x3 lattice vectors of the crystal, in bohr\n", |
| 174 | + " :param reference_distance: distance between consecutive k-points in the band structure.\n", |
| 175 | + " :param g_vectors_range: integer indicating how many G vectors should be included\n", |
| 176 | + " to compute the band structure.\n", |
| 177 | + " \"\"\"\n", |
| 178 | + " \n", |
171 | 179 | " # Simple way to get automatically the band path:\n",
|
172 | 180 | " # I go back to real space, just put a single atom at the origin,\n",
|
173 | 181 | " # then go back with seekpath.\n",
|
|
213 | 221 | "metadata": {},
|
214 | 222 | "outputs": [],
|
215 | 223 | "source": [
|
216 |
| - "%matplotlib widget\n", |
217 |
| - "\n", |
218 |
| - "import time\n", |
219 |
| - "import matplotlib.pyplot as plt\n", |
220 |
| - "from ipywidgets import Output, Button, RadioButtons, IntSlider, HBox, VBox, Checkbox, Label, FloatSlider\n", |
| 224 | + "from ipywidgets import RadioButtons, HBox, VBox\n", |
221 | 225 | "\n",
|
222 | 226 | "alat_bohr = 7.72\n",
|
223 | 227 | "\n",
|
224 |
| - "lattices = np.zeros((3, 3, 3));\n", |
| 228 | + "lattices = np.zeros((3, 3, 3))\n", |
225 | 229 | "\n",
|
226 |
| - "lattices[0] = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) * alat_bohr / 2.0;\n", |
227 |
| - "lattices[1] = np.array([[0, 1, 1], [1, 0, 1], [1, 1, 0]]) * alat_bohr / 2.0;\n", |
228 |
| - "lattices[2] = np.array([[-1, 1, 1], [1, -1, 1], [1, 1, -1]]) * alat_bohr / 2.0;\n", |
| 230 | + "lattices[0] = np.array([[1, 0, 0], [0, 1, 0], [0, 0, 1]]) * alat_bohr / 2.0\n", |
| 231 | + "lattices[1] = np.array([[0, 1, 1], [1, 0, 1], [1, 1, 0]]) * alat_bohr / 2.0\n", |
| 232 | + "lattices[2] = np.array([[-1, 1, 1], [1, -1, 1], [1, 1, -1]]) * alat_bohr / 2.0\n", |
229 | 233 | "\n",
|
230 | 234 | "real_lattice_bohr = lattices[0]\n",
|
231 |
| - "bz = BZVisualizer(real_lattice_bohr, [[0.0, 0.0, 0.0]], [1], True, height='400px')" |
| 235 | + "bz = BZVisualizer(real_lattice_bohr, [[0.0, 0.0, 0.0]], [1], height='400px', show_pathpoints = True, disable_interact_overlay = True)" |
232 | 236 | ]
|
233 | 237 | },
|
234 | 238 | {
|
|
239 | 243 | },
|
240 | 244 | "outputs": [],
|
241 | 245 | "source": [
|
242 |
| - "#G = Cell(real_lattice_bohr).reciprocal()*2*np.pi\n", |
| 246 | + "def unicode_gamma(label):\n", |
| 247 | + " if label == \"GAMMA\":\n", |
| 248 | + " return 'Γ'\n", |
| 249 | + " return label\n", |
243 | 250 | "\n",
|
244 |
| - "style = {'description_width': 'initial'}\n", |
| 251 | + "def free_electron_aiida_bands(segments_data):\n", |
| 252 | + " \"\"\"\n", |
| 253 | + " Turns the free electron bandstructure segments data into\n", |
| 254 | + " the AiiDA format that can be used with the widget-bandsplot\n", |
| 255 | + " \"\"\"\n", |
| 256 | + " path = []\n", |
| 257 | + " paths = []\n", |
| 258 | + " for seg in segments_data:\n", |
| 259 | + " from_label = unicode_gamma(seg[\"start_label\"])\n", |
| 260 | + " to_label = unicode_gamma(seg[\"end_label\"])\n", |
| 261 | + " path.append([from_label, to_label])\n", |
| 262 | + " paths.append({\n", |
| 263 | + " \"length\": len(seg['kpoints_x']),\n", |
| 264 | + " \"from\": from_label,\n", |
| 265 | + " \"to\": to_label,\n", |
| 266 | + " \"two_band_types\": False,\n", |
| 267 | + " \"x\": seg[\"kpoints_x\"].tolist(),\n", |
| 268 | + " \"values\": seg[\"energy_bands\"].tolist(),\n", |
| 269 | + " })\n", |
245 | 270 | "\n",
|
246 |
| - "output = Output()\n", |
| 271 | + " return {\n", |
| 272 | + " \"label\": \"\",\n", |
| 273 | + " \"path\": path,\n", |
| 274 | + " \"paths\": paths,\n", |
| 275 | + " #\"fermi_level\": 0,\n", |
| 276 | + " }\n", |
| 277 | + "\n", |
| 278 | + "style = {'description_width': 'initial'}\n", |
247 | 279 | "cell_type = RadioButtons(options=['Simple cubic', 'FCC', 'BCC'], value='Simple cubic', description=\"Cell type:\")\n",
|
248 |
| - "nkpt = IntSlider(value=4, min=4, max=11, description=\"Number of k-point:\", style=style)\n", |
249 |
| - "grange = IntSlider(value=0, min=0, max=3, description=\"Gvector range:\", style=style)\n", |
250 |
| - "gcov = FloatSlider(value=0.5, min=0.1, max=1.0, description=\"Guassian covariance:\", style=style)\n", |
251 | 280 | "\n",
|
252 | 281 | "def on_celltype_changed(c):\n",
|
253 | 282 | " global real_lattice_bohr\n",
|
254 | 283 | " real_lattice_bohr = lattices[cell_type.index]\n",
|
255 |
| - " ax.clear()\n", |
256 |
| - "\n", |
257 |
| - " plot_bandstructure('bands')\n", |
258 | 284 | " bz.cell = real_lattice_bohr.tolist()\n",
|
| 285 | + " print(\"test\")\n", |
| 286 | + " \n", |
| 287 | + " plot_bandstructure()\n", |
259 | 288 | "\n",
|
260 |
| - "cell_type.observe(on_celltype_changed, names='value');\n", |
261 |
| - "\n", |
| 289 | + "cell_type.observe(on_celltype_changed, names='value')\n", |
262 | 290 | "\n",
|
263 |
| - "def plot_bandstructure(c):\n", |
264 |
| - " global G, segments_data, lbands\n", |
265 |
| - " \n", |
| 291 | + "def plot_bandstructure():\n", |
266 | 292 | " segments_data = get_bands(real_lattice_bohr)\n",
|
267 |
| - " G = np.array([segments_data[0]['b1'], segments_data[0]['b2'], segments_data[0]['b3']])\n", |
268 |
| - " \n", |
269 |
| - " x_ticks = []\n", |
270 |
| - " x_labels = []\n", |
271 |
| - " lbands = []\n", |
272 |
| - "\n", |
273 |
| - " for segment_data in segments_data:\n", |
274 |
| - " if not x_labels:\n", |
275 |
| - " x_labels.append(prettify(segment_data['start_label']))\n", |
276 |
| - " x_ticks.append(segment_data['kpoints_x'][0])\n", |
277 |
| - " else:\n", |
278 |
| - " if x_labels[-1] != prettify(segment_data['start_label']):\n", |
279 |
| - " x_labels[-1] += \"|\" + prettify(segment_data['start_label'])\n", |
280 |
| - " x_labels.append(prettify(segment_data['end_label']))\n", |
281 |
| - " x_ticks.append(segment_data['kpoints_x'][-1])\n", |
282 |
| - "\n", |
283 |
| - " for energy_band in segment_data['energy_bands']:\n", |
284 |
| - " line, = ax.plot(segment_data['kpoints_x'], energy_band, 'k')\n", |
285 |
| - " lbands.append(line)\n", |
286 |
| - "\n", |
287 |
| - " ax.set_ylim([0, 5])\n", |
288 |
| - " ax.yaxis.tick_right()\n", |
289 |
| - " ax.yaxis.set_label_position(\"right\")\n", |
290 |
| - " ax.set_ylabel('Free-electron energy (eV)')\n", |
291 |
| - " ax.set_xlim([np.min(x_ticks), np.max(x_ticks)])\n", |
292 |
| - " ax.set_xticks(x_ticks)\n", |
293 |
| - " ax.set_xticklabels(x_labels)\n", |
294 |
| - " ax.grid(axis='x', color='red', linestyle='-', linewidth=0.5)\n", |
295 |
| - " fig.tight_layout()\n", |
296 |
| - " \n", |
297 |
| - " update_bands_color('bands')\n", |
298 |
| - " \n", |
299 |
| - "def update_bands_color(c):\n", |
300 |
| - " n = 3\n", |
301 |
| - " \n", |
302 |
| - " shape = (nkpt.value, nkpt.value, nkpt.value)\n", |
303 |
| - " kpts = np.dot(monkhorst_pack(shape), G).reshape(shape + (3,))\n", |
304 |
| - " eigs = _compute_dos(kpts, G, grange.value)\n", |
| 293 | + " aiida_bands = free_electron_aiida_bands(segments_data)\n", |
| 294 | + " bands_widget.bands = [aiida_bands]\n", |
305 | 295 | "\n",
|
306 |
| - " index = 0\n", |
307 |
| - " \n", |
308 |
| - " for segment_data in segments_data:\n", |
309 |
| - " for i in range(-n, n+1):\n", |
310 |
| - " for j in range(-n, n+1):\n", |
311 |
| - " for k in range(-n, n+1): \n", |
312 |
| - " if abs(i) <= grange.value and abs(j) <= grange.value and abs(k) <=grange.value:\n", |
313 |
| - " lbands[index].set_color('r')\n", |
314 |
| - " else:\n", |
315 |
| - " lbands[index].set_color('k')\n", |
316 |
| - " index+=1\n", |
317 |
| - "\n", |
318 |
| - "grange.observe(update_bands_color, names=\"value\")\n", |
319 | 296 | "\n",
|
320 |
| - " \n", |
321 |
| - "with output:\n", |
322 |
| - " global fig, ax\n", |
323 |
| - " fig, ax = plt.subplots()\n", |
324 |
| - " fig.set_size_inches(3.7, 5.0)\n", |
325 |
| - " fig.canvas.header_visible = False\n", |
326 |
| - " fig.canvas.layout.width = \"430px\"\n", |
327 |
| - " plot_bandstructure('bands')\n", |
328 |
| - " plt.show()\n", |
| 297 | + "from widget_bandsplot import BandsPlotWidget\n", |
329 | 298 | "\n",
|
330 |
| - " \n", |
331 |
| - "label1 = Label(value=\"Compute DOS by different methods:\")\n", |
332 |
| - "label2 = Label(value=\"(the number of k-points in all three dimensions)\")\n", |
333 |
| - "label3 = Label(value=\"(the number of G vector ranges in all three dimensions)\")" |
334 |
| - ] |
335 |
| - }, |
336 |
| - { |
337 |
| - "cell_type": "code", |
338 |
| - "execution_count": null, |
339 |
| - "metadata": {}, |
340 |
| - "outputs": [], |
341 |
| - "source": [ |
342 |
| - "display(HBox([VBox([bz,cell_type]), output]))" |
| 299 | + "bands_widget = BandsPlotWidget(\n", |
| 300 | + " energy_range = [0.0, 5.0],\n", |
| 301 | + " format_settings = {\"bandsYlabel\": \"Free electron energy (eV)\"}\n", |
| 302 | + ")\n", |
| 303 | + "plot_bandstructure()\n", |
| 304 | + "\n", |
| 305 | + "display(HBox([VBox([bz,cell_type]), bands_widget]))" |
343 | 306 | ]
|
344 | 307 | },
|
345 | 308 | {
|
346 | 309 | "cell_type": "markdown",
|
347 | 310 | "metadata": {},
|
348 | 311 | "source": [
|
349 |
| - "<details open>\n", |
350 |
| - " <summary style=\"font-size: 22px;\"><b>Legend</b></summary>\n", |
| 312 | + "## Legend\n", |
351 | 313 | "\n",
|
352 | 314 | "<p style=\"text-align: justify;font-size:15px\">\n",
|
353 | 315 | " The 1st Brillouin zone of the selected cell is shown on the left. \n",
|
354 | 316 | " The path along which the band structure is calculated is indicated with blue vectors and sampled\n",
|
355 | 317 | " k-points are shown with red dots.\n",
|
356 |
| - " \n", |
357 | 318 | " The figure on the right shows the calculated band structure. \n",
|
358 |
| - " \n", |
359 | 319 | " We provide three kinds of cell structure: simple cubic, \n",
|
360 | 320 | " face-centered cubic (FCC) and body-centered cubic (BCC). Use the radio \n",
|
361 |
| - " button to select the cell type. The number of k-points and G-vector ranges \n", |
362 |
| - " can be tuned with the sliders.\n", |
| 321 | + " button to select the cell type.\n", |
363 | 322 | "</p>\n",
|
364 | 323 | " "
|
365 | 324 | ]
|
|
388 | 347 | "name": "python",
|
389 | 348 | "nbconvert_exporter": "python",
|
390 | 349 | "pygments_lexer": "ipython3",
|
391 |
| - "version": "3.9.12" |
| 350 | + "version": "3.10.14" |
392 | 351 | }
|
393 | 352 | },
|
394 | 353 | "nbformat": 4,
|
|
0 commit comments