{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "GRABNES (GRAphene-BN-Electronic Structure) allows you to calculate the electronic properties of several types of layered materials, including the obvious combinations of graphene and h-BN, hence the name that was given to this package.\n", "\n", "One can build the systems for several basis systems using built-in methods which is useful as a first approximation when considering the rigid configurations. In reality, we often want to include lattice relaxation effects where we read in the structure given as output from LAMMPS (for example) as input for the GRABNES code. The go-to method in that case is ReadXYZ.\n", "\n", "In this tutorial, we are going to first use the build-in methods to build the systam and calculate some observables for them while after we are going to focus on the ReadXYZ approach.\n", "\n", "A few useful post-processing code-snippets are given at the end of the notebook." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Built-in methods" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Graphene" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Gendata_graphene.in allows you to build graphene systems. Run it using the `grabnes` executable in `bin` to make sure it runs correctly.\n", "- Modify it to build systems of different sizes, using `CellSize`. Check in the source code what this flag means. Get familiar with `grep -r \"SuperCell .\"`-style commands to find all the occurences of a certain flag inside the source code.\n", "- Modify the output files `generate.pos` or `pos` to your needs to visualize it using `VESTA`, `VMD`, `xcrysden` or any other of your favorite tools." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Graphene with hBN, using effective model" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's switch our attention to graphene on hBN using the effective model introduced in [Jeil Jung, PRB 89, 205414 (2014)]. For this, we can use (some of) the following input flags:\n", "- `MoirePotential .true.`\n", "- `MoireJeil .true.`\n", "- `MoireOffDiag .true.`\n", "- `MoireOnlyH0 .false.`\n", "- `MoireOnlyHZ .false.`\n", "- `MoireNoH0AndHZ .false.`\n", "- `MoireH0AndHZ .true.`\n", "- `MoirePotC0 0-0.01013`\n", "- `MoirePotCz 0-0.00901`\n", "- `MoirePotCab 0.01134`\n", "- `MoirePotPhi0 1.510233401750693`\n", "- `MoirePotPhiz 0.147131255943122`\n", "- `MoirePotPhiab 0.342084533390889`\n", "- `Latticepercent 0-0.018181818181818` \n", "\n", "Tasks:\n", "- The value for the last flag works for a `55x55`-sized system. Why is that?\n", "- Modify the value for a `56x56`-sized system.\n", "- Why is there a negative sign in front of this value?\n", "- Plot the onsite energies for each of the atoms using a scatter plot where the color matches those energies. Confirm that the resulting moire pattern is periodic.\n", "- Calculate the DOS for a single moire unit cell using Lanczos recursion. Plot out the data in the resulting `generate.DOS`. Why does the plot look spiky?\n", "- Run a convergence study on this DOS by increasing the `SuperCell` value.\n", "- Calculate the DOS using exact diagonalization.\n", "- Calculate the electronic bandstructure of this system.\n", "- Add a magnetic field to this system and repeat the previous steps. Why can't you use exact diagonalization for this? Hint: read up on the Peierls phase substitution, see for instance Ref. [A. Cresti, Phys. Rev. B 103, 045402 (2021)].\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Twisted bilayer graphene" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A common way to describe a moire system is using the 4 indices defined by Hermann.\n", "\n", "Tasks:\n", "- Create a twisted bilayer system using the `31 30 30 31` indices and visualize the structure.\n", "- Calculate the electronic bandstructure and visualize the flat band.\n", "- Calculate the DOS and optimize the supercell size to get clear signatures." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# ReadXYZ" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Twisted bilayer graphene" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Repeat the twisted bilayer graphene calculations from the previous section using the relaxed structure given for download here.\n", "- Compare the results for the previous rigid configuration with the relaxed configuration observables." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Graphene on h-BN" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "- Calculate the bandstructure for this system using the input file and structure given in the shared folder." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Code snippets" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "import os\n", "\n", "def latexify(fig_width=None, fig_height=None, columns=1):\n", " \"\"\"Set up matplotlib's RC params for LaTeX plotting.\n", " Call this before plotting a figure.\n", "\n", " Parameters\n", " ----------\n", " fig_width : float, optional, inches\n", " fig_height : float, optional, inches\n", " columns : {1, 2}\n", " \"\"\"\n", "\n", " # code adapted from http://www.scipy.org/Cookbook/Matplotlib/LaTeX_Examples\n", "\n", " # Width and max height in inches for IEEE journals taken from\n", " # computer.org/cms/Computer.org/Journal%20templates/transactions_art_guide.pdf\n", "\n", " assert(columns in [1,2])\n", "\n", " if fig_width is None:\n", " fig_width = 3.39 if columns==1 else 6.9 # width in inches\n", "\n", " if fig_height is None:\n", " golden_mean = (sqrt(5)-1.0)/2.0 # Aesthetic ratio\n", " fig_height = fig_width*golden_mean # height in inches\n", "\n", " #MAX_HEIGHT_INCHES = 7.0\n", " #if fig_height > MAX_HEIGHT_INCHES:\n", " # print(\"WARNING: fig_height too large:\" + fig_height + \n", " # \"so will reduce to\" + MAX_HEIGHT_INCHES + \"inches.\")\n", " # fig_height = MAX_HEIGHT_INCHES\n", "\n", " params = {'backend': 'ps',\n", " 'text.latex.preamble': [r'\\usepackage{gensymb}'],\n", " 'axes.labelsize': 8, # fontsize for x and y labels (was 10)\n", " 'axes.titlesize': 8,\n", " 'font.size': 8, # was 10\n", " 'legend.fontsize': 8, # was 10\n", " 'xtick.labelsize': 8,\n", " 'ytick.labelsize': 8,\n", " 'text.usetex': True,\n", " 'figure.figsize': [fig_width,fig_height],\n", " 'font.family': 'serif',\n", " 'figure.autolayout': True,\n", " 'lines.linewidth' : 1.0\n", " }\n", "\n", " matplotlib.rcParams.update(params)\n", "\n", "\n", "def format_axes(ax):\n", " \n", " SPINE_COLOR = 'gray'\n", "\n", " for spine in ['top', 'right']:\n", " ax.spines[spine].set_visible(False)\n", "\n", " for spine in ['left', 'bottom']:\n", " ax.spines[spine].set_color(SPINE_COLOR)\n", " ax.spines[spine].set_linewidth(0.5)\n", "\n", " ax.xaxis.set_ticks_position('bottom')\n", " ax.yaxis.set_ticks_position('left')\n", "\n", " for axis in [ax.xaxis, ax.yaxis]:\n", " axis.set_tick_params(direction='out', color=SPINE_COLOR)\n", "\n", "#q_sigma = c0 * 22.2 # [nm] hopping fitting parameter\n", "#q_pi = a_cc * 22.2 # [nm] hopping fitting parameter\n", "#r0 = 0.184 * a # [nm] hopping fitting parameter\n", "\n", "\n", "\n", "\n", "from mpl_toolkits.axes_grid1 import make_axes_locatable\n", "\n", "\n", "def getBandstructure(dir1, nPlotBands, EShift):\n", "\n", " f = open(dir1+'/generate.bands.dat','r')\n", " print(f)\n", " \n", " \n", " i = 0\n", " j = 0\n", " l = 0\n", " \n", " k = []\n", " E = []\n", " \n", " kVec = []\n", " EVec = []\n", " \n", " counterPlotBands = 0\n", " \n", " for line in f:\n", " i = i+1\n", " a = line.split()\n", " if i==10:\n", " nbands = int(a[5])\n", " print(nbands)\n", " nk = int(a[7])\n", " print(nbands,nk)\n", " if i>16:\n", " if len(a)==0:\n", " j = j+0.5\n", " #print(j)\n", " else:\n", " if (int(j)==int(nbands/2-nPlotBands/2 + counterPlotBands) and int(j) < int(nbands/2+nPlotBands/2)):\n", " if l14:\n", " if len(a)==0:\n", " j = j+0.5\n", " #print(j)\n", " else:\n", " #print(nbands)\n", " if (int(j)==int(nbands/2) + bandIndex):\n", " if lEmax):\n", " Emax = np.max(EVec)\n", " #if (np.min(EVec)Emax):\n", " Emax = np.max(EVec)\n", " #if (np.min(EVec)chosenEnergy-cutoffMin,eig0.0)] = 1.0\n", " specSum = np.sum(spec[np.logical_and(np.logical_and(eig>chosenEnergy-cutoffMin,eig0.0)])\n", " if (eigTrue.any()==1):\n", " eigTrueVec.append(specSum)\n", " else:\n", " eigTrueVec.append(0)\n", " \n", "\n", " return k, eigTrueVec \n", " \n", "K1 = np.array([1.70276024584813, 0.0000])\n", "K1p = np.array([1.70243417150001, 3.332186294066186E-002])\n", "\n", "\n", "def getEnergyCutPlot2(dir1, chosenEnergy, Nx, Ny, cutoffMin, cutoffMax, nEnergy):\n", "\n", " os.chdir(dir1)\n", " \n", "\n", " data = np.genfromtxt(\"generate.spectral\")\n", " kx = data[:,0]\n", " ky = data[:,1]\n", " kz = data[:,2]\n", " energy = (data[:,3]*3.5)-0.31\n", " spectral = data[:,4]\n", " \n", " cutoffMin = cutoff\n", " cutoffMax = cutoff\n", " \n", " i = 0\n", " j = 0\n", " eigVec = []\n", " spectralVec = []\n", " \n", " eig = np.zeros(nEnergy)\n", " spect = np.zeros(nEnergy)\n", " k = np.zeros(shape=(Nx*Ny,2))\n", " \n", " for el1, el2, el3, el4 in zip(kx,ky,energy,spectral):\n", " i = i+1\n", " if (i==1):\n", " k[j,0] = el1\n", " k[j,1] = el2\n", " if (i<=nEnergy):\n", " eig[i-1] = el3\n", " spect[i-1] = el4\n", " if (i==nEnergy):\n", " eigVec.append(eig)\n", " spectralVec.append(spect)\n", " i = 0\n", " j = j+1\n", " eig = np.zeros(nEnergy)\n", " spect = np.zeros(nEnergy)\n", " \n", " \n", " eigTrueVec = []\n", " for i, kki in enumerate(k):\n", " eigTrue = np.zeros(nEnergy)\n", " eig = eigVec[i]\n", " spec = spectralVec[i]\n", " eigTrue[np.logical_and(np.logical_and(eig>chosenEnergy-cutoffMin,eig0.0)] = 1.0\n", " specSum = np.sum(spec[np.logical_and(np.logical_and(eig>chosenEnergy-cutoffMin,eig0.0)])\n", " if (eigTrue.any()==1):\n", " eigTrueVec.append(specSum)\n", " else:\n", " eigTrueVec.append(0)\n", " \n", "\n", " return k, eigTrueVec \n", "\n", "def getDOS(fileName):\n", " data = np.genfromtxt(fileName)\n", " xdata = data[:,0]\n", " ydata = data[:,1]\n", " return xdata, ydata\n", " \n", "K1 = np.array([1.70276024584813, 0.0000])\n", "K1p = np.array([1.70243417150001, 3.332186294066186E-002])" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }