From 43d3a2d01af62386a691db8332c630db8a7b8741 Mon Sep 17 00:00:00 2001
From: Kostas Vilkelis <kostasvilkelis@gmail.com>
Date: Wed, 12 Feb 2020 00:30:33 +0000
Subject: [PATCH] edit intro to lecture 9, add figures

---
 src/10_xray.md             | 191 +++++++++++++++++++-
 src/9_crystal_structure.md | 361 ++++++++++++++++++++++++++++---------
 2 files changed, 466 insertions(+), 86 deletions(-)

diff --git a/src/10_xray.md b/src/10_xray.md
index 96645920..2493d7b3 100644
--- a/src/10_xray.md
+++ b/src/10_xray.md
@@ -1,3 +1,34 @@
+---
+jupyter:
+  jupytext:
+    text_representation:
+      extension: .md
+      format_name: markdown
+      format_version: '1.0'
+      jupytext_version: 1.0.2
+  kernelspec:
+    display_name: Python 3
+    language: python
+    name: python3
+---
+
+```{python initialize=true}
+import matplotlib.pyplot as plt
+
+import numpy as np
+from math import sqrt,pi
+
+from common import draw_classic_axes, configure_plotting
+
+import plotly.offline as py
+from plotly.subplots import make_subplots
+import plotly.graph_objs as go
+
+configure_plotting()
+
+py.init_notebook_mode(connected=True)
+```
+
 _based on chapters 13.1-13.2 & 14.1-14.2 of the book_  
 
 !!! summary "Learning goals"
@@ -68,7 +99,165 @@ which is clearly 1.
 
 ### Example of a two-dimensional reciprocal lattice
 
-![](figures/reciprocal_mod.svg)
+```python
+# Define the lattice vectors
+a1 = np.array([1,0])
+a2 = np.array([0.5,sqrt(3)/2])
+a1_alt = -a1-a2
+a2_alt = a1_alt + a1
+a2_c = np.array([0,sqrt(3)])
+
+# Produces the lattice to be fed into plotly
+def lattice_generation(a1,a2,N=6):
+    grid = np.arange(-N//2,N//2,1)
+    xGrid, yGrid = np.meshgrid(grid,grid)
+    return np.reshape(np.kron(xGrid.flatten(),a1),(-1,2))+np.reshape(np.kron(yGrid.flatten(),a2),(-1,2))
+
+
+# Produces the dotted lines of the unit cell
+def dash_contour(a1,a2, vec_zero = np.array([0,0]), color='Red'):
+    dotLine_a1 = np.transpose(np.array([a1,a1+a2])+vec_zero)
+    dotLine_a2 = np.transpose(np.array([a2,a1+a2])+vec_zero)
+    
+    def dash_trace(vec,color): 
+        trace = go.Scatter(
+            x=vec[0], 
+            y=vec[1], 
+            mode = 'lines', 
+            line_width = 2, 
+            line_color = color, 
+            line_dash='dot',
+            visible=False
+        )
+        return trace
+    
+    return dash_trace(dotLine_a1,color),dash_trace(dotLine_a2,color)
+
+# Makes the lattice vector arrow
+def make_arrow(vec,text,color = 'Red',vec_zero = [0,0],text_shift = [-0.2,-0.1]):
+    annot = [dict(
+            x=vec[0]+vec_zero[0],
+            y=vec[1]+vec_zero[1],
+            ax=vec_zero[0],
+            ay=vec_zero[1],
+            xref='x',
+            yref='y',
+            axref='x',
+            ayref = 'y',
+            showarrow=True,
+            arrowhead=2,
+            arrowsize=1,
+            arrowwidth=3, 
+            arrowcolor = color
+                 ),
+         dict(
+            x=(vec[0]+vec_zero[0])/2+text_shift[0],
+            y=(vec[1]+vec_zero[1])/2+text_shift[1],
+            xref='x',
+            ayref = 'y',
+            text = text,
+            font = dict(
+                color = color,
+                size = 20
+            ),
+            showarrow=False,
+             )
+        ]
+    return annot
+
+# Create the pattern
+pattern_points = lattice_generation(a1,a2)
+pattern = go.Scatter(x=pattern_points.T[0],y=pattern_points.T[1],mode='markers',marker=dict( 
+    color='Black', 
+    size = 20,
+    symbol = 'star-open-dot')
+    )
+
+# Lattice Choice A
+latticeA = go.Scatter(visible = False,x=pattern_points.T[0],y=pattern_points.T[1],mode='markers',marker=dict(
+        color='Red',
+        size = 10,
+        )
+    )
+
+# Lattice Choice B
+latB_points = lattice_generation(a1,a2)
+latticeB = go.Scatter(visible = False, x=latB_points.T[0]+0.5,y=latB_points.T[1],mode='markers',marker=dict(
+        color='Blue',
+        size = 10,
+        )
+    )
+
+# Annotate the lattice vectors
+# Button 2 
+bt2_annot = make_arrow(a1,'$a_1$') + make_arrow(a2,'$a_2$') + make_arrow(a1_alt,'$a`_1$',color='Black',text_shift=[-0.55,-0.1]) + make_arrow(a2_alt,'$a`_2$',color='Black')
+#Button 3
+bt3_annot =  make_arrow(a1,'$a_1$', vec_zero = [-0.5,0], color = 'Blue') + make_arrow(a2,'$a_2$',vec_zero = [-0.5,0], color = 'Blue')
+#Button 4
+bt4_annot =  make_arrow(a2_c,'$a_2$') + make_arrow(a1,'$a_1$')
+
+# (0)  Button 1, (0, 1-5) Button 2, (0, 6-8) Button 3, (0,1,9,10)
+data = [pattern,latticeA,*dash_contour(a1,a2),*dash_contour(a1_alt,a2_alt,color='Black'),
+        latticeB, *dash_contour(a1,a2,vec_zero=[-0.5,0],color='Blue'), 
+        *dash_contour(a1, a2_c)]
+
+
+updatemenus=list([ 
+    dict(
+        type="buttons",
+        direction="down",
+        active=0,
+        buttons=list([
+            dict(label="Pattern",
+                 method="update",
+                 args=[{"visible": [True, False, False, False, False, False, False, False, False, False, False]},
+                       {"title": "Pattern",
+                        "annotations": []}]),
+            dict(label="Lattice A",
+                 method="update",
+                 args=[{"visible": [True, True, True, True, True, True, False, False, False, False, False]},
+                       {"title": "Lattice A with a Primitive Unit Cell",
+                        "annotations": bt2_annot}]),
+            dict(label="Lattice B",
+                 method="update",
+                 args=[{"visible": [True, False, False, False, False, False, True, True, True, False, False]},
+                       {"title": "Lattice B with a Primitive Unit Cell",
+                        "annotations": bt3_annot}]),
+            dict(label="C.U.Cell",
+                 method="update",
+                 args=[{"visible": [True, True, False, False, False, False, False, False, False, True, True]},
+                       {"title": "Conventional Unit Cell",
+                        "annotations": bt4_annot}])
+        ]),
+    )
+]
+)
+
+
+plot_range = 2
+axis = dict(
+        range=[-plot_range,plot_range],
+        visible = False,
+        showgrid = False,
+        fixedrange = True
+    )
+
+layout = dict(
+    showlegend = False,
+    updatemenus=updatemenus,
+    plot_bgcolor = 'rgb(254, 254, 254)',
+    width = 600,
+    height = 600,
+    xaxis = axis,
+    yaxis = axis
+)
+
+
+
+fig=dict(data=data, layout=layout)
+py.iplot(fig, filename='lattice_basics')
+
+```
 
 Compose reciprocal lattice vectors.
 Directions:
diff --git a/src/9_crystal_structure.md b/src/9_crystal_structure.md
index d345c654..a1d53cca 100644
--- a/src/9_crystal_structure.md
+++ b/src/9_crystal_structure.md
@@ -16,11 +16,12 @@ jupyter:
 import matplotlib.pyplot as plt
 
 import numpy as np
-from math import sqrt
+from math import sqrt,pi
 
 from common import draw_classic_axes, configure_plotting
 
 import plotly.offline as py
+from plotly.subplots import make_subplots
 import plotly.graph_objs as go
 
 configure_plotting()
@@ -43,28 +44,196 @@ _based on chapter 12 of the book_
 
 ### Crystal classification
 
-- **_Lattice_**
-    + periodic pattern of *lattice points*, which all have an identical view
-    + lattice points are not necessarily the same as atom positions
-    + there can be multiple atoms per lattice point
-    + freedom of translation
-    + multiple lattices with different point densities possible
-- **_Lattice vectors_**
-    + from lattice point to lattice point
-    + $N$ linearly independent vectors for $N$ dimensions
-    + integer combinations are also lattice vectors
-    + not all sets of linearly independent lattice vectors provide full coverage of the lattice
-- **_Unit cell_**
-    + spanned by lattice vectors
-    + has 4 corners in 2D, 8 corners in 3D
-    + copying unit cell along lattice vectors gives full lattice
-- **_Primitive unit cell_**
-    + unit cell that contains exactly 1 lattice point
-    + not always most practical choice
-- **_Basis_**
-    + only now do we care about the contents (i.e. atoms)
-    + gives types and positions of atoms
-    + two conventions: Cartesian coordinates or lattice coordinates
+```python
+# Define the lattice vectors
+a1 = np.array([1,0])
+a2 = np.array([0.5,sqrt(3)/2])
+a1_alt = -a1-a2
+a2_alt = a1_alt + a1
+a2_c = np.array([0,sqrt(3)])
+
+# Produces the lattice to be fed into plotly
+def lattice_generation(a1,a2,N=6):
+    grid = np.arange(-N//2,N//2,1)
+    xGrid, yGrid = np.meshgrid(grid,grid)
+    return np.reshape(np.kron(xGrid.flatten(),a1),(-1,2))+np.reshape(np.kron(yGrid.flatten(),a2),(-1,2))
+
+
+# Produces the dotted lines of the unit cell
+def dash_contour(a1,a2, vec_zero = np.array([0,0]), color='Red'):
+    dotLine_a1 = np.transpose(np.array([a1,a1+a2])+vec_zero)
+    dotLine_a2 = np.transpose(np.array([a2,a1+a2])+vec_zero)
+    
+    def dash_trace(vec,color): 
+        trace = go.Scatter(
+            x=vec[0], 
+            y=vec[1], 
+            mode = 'lines', 
+            line_width = 2, 
+            line_color = color, 
+            line_dash='dot',
+            visible=False
+        )
+        return trace
+    
+    return dash_trace(dotLine_a1,color),dash_trace(dotLine_a2,color)
+
+# Makes the lattice vector arrow
+def make_arrow(vec,text,color = 'Red',vec_zero = [0,0],text_shift = [-0.2,-0.1]):
+    annot = [dict(
+            x=vec[0]+vec_zero[0],
+            y=vec[1]+vec_zero[1],
+            ax=vec_zero[0],
+            ay=vec_zero[1],
+            xref='x',
+            yref='y',
+            axref='x',
+            ayref = 'y',
+            showarrow=True,
+            arrowhead=2,
+            arrowsize=1,
+            arrowwidth=3, 
+            arrowcolor = color
+                 ),
+         dict(
+            x=(vec[0]+vec_zero[0])/2+text_shift[0],
+            y=(vec[1]+vec_zero[1])/2+text_shift[1],
+            xref='x',
+            ayref = 'y',
+            text = text,
+            font = dict(
+                color = color,
+                size = 20
+            ),
+            showarrow=False,
+             )
+        ]
+    return annot
+
+# Create the pattern
+pattern_points = lattice_generation(a1,a2)
+pattern = go.Scatter(x=pattern_points.T[0],y=pattern_points.T[1],mode='markers',marker=dict( 
+    color='Black', 
+    size = 20,
+    symbol = 'star-open-dot')
+    )
+
+# Lattice Choice A
+latticeA = go.Scatter(visible = False,x=pattern_points.T[0],y=pattern_points.T[1],mode='markers',marker=dict(
+        color='Red',
+        size = 10,
+        )
+    )
+
+# Lattice Choice B
+latB_points = lattice_generation(a1,a2)
+latticeB = go.Scatter(visible = False, x=latB_points.T[0]+0.5,y=latB_points.T[1],mode='markers',marker=dict(
+        color='Blue',
+        size = 10,
+        )
+    )
+
+# Annotate the lattice vectors
+# Button 2 
+bt2_annot = make_arrow(a1,'$a_1$') + make_arrow(a2,'$a_2$') + make_arrow(a1_alt,'$a`_1$',color='Black',text_shift=[-0.55,-0.1]) + make_arrow(a2_alt,'$a`_2$',color='Black')
+#Button 3
+bt3_annot =  make_arrow(a1,'$a_1$', vec_zero = [-0.5,0], color = 'Blue') + make_arrow(a2,'$a_2$',vec_zero = [-0.5,0], color = 'Blue')
+#Button 4
+bt4_annot =  make_arrow(a2_c,'$a_2$') + make_arrow(a1,'$a_1$')
+
+# (0)  Button 1, (0, 1-5) Button 2, (0, 6-8) Button 3, (0,1,9,10)
+data = [pattern,latticeA,*dash_contour(a1,a2),*dash_contour(a1_alt,a2_alt,color='Black'),
+        latticeB, *dash_contour(a1,a2,vec_zero=[-0.5,0],color='Blue'), 
+        *dash_contour(a1, a2_c)]
+
+
+updatemenus=list([ 
+    dict(
+        type="buttons",
+        direction="down",
+        active=0,
+        buttons=list([
+            dict(label="Pattern",
+                 method="update",
+                 args=[{"visible": [True, False, False, False, False, False, False, False, False, False, False]},
+                       {"title": "Pattern",
+                        "annotations": []}]),
+            dict(label="Lattice A",
+                 method="update",
+                 args=[{"visible": [True, True, True, True, True, True, False, False, False, False, False]},
+                       {"title": "Lattice A with a Primitive Unit Cell",
+                        "annotations": bt2_annot}]),
+            dict(label="Lattice B",
+                 method="update",
+                 args=[{"visible": [True, False, False, False, False, False, True, True, True, False, False]},
+                       {"title": "Lattice B with a Primitive Unit Cell",
+                        "annotations": bt3_annot}]),
+            dict(label="C.U.Cell",
+                 method="update",
+                 args=[{"visible": [True, True, False, False, False, False, False, False, False, True, True]},
+                       {"title": "Conventional Unit Cell",
+                        "annotations": bt4_annot}])
+        ]),
+    )
+]
+)
+
+
+plot_range = 2
+axis = dict(
+        range=[-plot_range,plot_range],
+        visible = False,
+        showgrid = False,
+        fixedrange = True
+    )
+
+layout = dict(
+    showlegend = False,
+    updatemenus=updatemenus,
+    plot_bgcolor = 'rgb(254, 254, 254)',
+    width = 600,
+    height = 600,
+    xaxis = axis,
+    yaxis = axis
+)
+
+
+fig=dict(data=data, layout=layout)
+py.iplot(fig, filename='lattice_basics')
+
+```
+
+Most of solid state physics deals with periodic crystals. To describe a periodic structure, we need a simple framework to work with. Such a framework is given by the concept of a **lattice**:
+
+> A **lattice** is an infinite set of points defined by integer sums of a set of linearly independent **primitive lattice vectors**.
+$$
+\begin{equation}
+\mathbf{R}_{\left[n_{1} n_{2} n_{3}\right]}=n_{1} \mathbf{a}_{1}+n_{2} \mathbf{a}_{2}+n_{3} \mathbf{a}_{3} \quad n_{1}, n_{2}, n_{3} \in \mathbb{Z}
+\end{equation}
+$$
+
+That is pretty rigorous. A more practical, equivalent definition is: 
+
+> A **lattice** is a set of points where the environment of any given point is equivalent to the environment of any other given point.
+
+Lets put these into practice. In the plot's 'Pattern' tab below, a simple $\star$ pattern is presented. 
+
+There are several ways to assign lattice points to the plot. One such option is given in the plot's 'Lattice A' tab. As the first definition suggests, we can define **primitive lattice vectors** connecting these lattice points. Again, the choice of primitive lattice vectors is not unique given a lattice. Both the black and red vectors are equally good definitions since their integer linear combinations are able to map out all of the lattice points (try it out!)
+
+Does the choice of a lattice need to coincide with the centre of our arbitrary $\star$ pattern? Nope! In the 'Lattice B' tab, we can see another choice of the lattice. One can confirm that around each lattice point the surroundings are the same, fulfilling our second definition of a lattice. Since the lattice points are shifted from the $\star$, we need to include that information in order to reconstruct the pattern from the lattice alone. This can be done with a concept of **basis**
+
+> The description of objects with respect to the reference lattice point is known as a **basis**.
+
+The reference lattice point is the chosen lattice point to which we apply the lattice vectors in order to reconstruct the lattice.
+In the 'Lattice A' case, the basis is trivial $\star = (0,0)$ since each lattice points corresponds with the $\star$ object. In 'Lattice B', each object is shifted half a $a_1$ away from the lattice point. Therefore, its basis is $\star = (1/2,0)$ in fractional coordinates. The basis is especially important when a crystal has many different types of atoms (for example manny salts like NaCl)
+
+Rather than work with the whole space of the crystal, it is practical to use the smallest possible 'building block' of the crystal - a **unit cell**: 
+
+> A **unit cell** is a region of space such that when many identical units are stacked together it tiles (completely fills) all of space and reconstructs the full structure.
+
+The most straightforward way to construct a unit cell is through the **primitive lattice vectors** as shown in the 'Lattice A' and 'Lattice B' tabs via the extended dotted lines. Such a construction is known as a **primitive unit cell** since it contains only 1 lattice point. One can confirm this by noting that each primitive unit cell shares its corner lattice points with 4 neighbouring cells. Therefore, $\frac{1}{4} \times 4 = 1$, confirming our definition.
+
+A primitive unit cell might not be the most practical choice due to non-orthogonal axes. However, we can always define a **conventional unit cell** with an orthogonal set of lattice vectors as shown in 'C.U.Cell' tab. Conventional unit cells have multiple lattice points as seen in this case since there is an additional lattice point at the centre belonging solely to each cell. As such, there are $1 + \frac{1}{4} \times 4 = 2 $ lattice points. There is a slight problem with this definition of lattice vectors - no integer linear combination of lattice vectors is able to produce the centre lattice points in the unit cell. In order to be able to reproduce the pattern, we need to include that information and the easiest way to do so is through our definition of basis. Since there is one $\star$ at the corner of the unit cell, and one at the centre, the basis is $\star = (0,0),(1/2,1/2)$. One can view this as saying that the complete lattice is made up from two interpenetrating orthogonal lattices - one centred at $(0,0)$ and another at $(1/2,1/2)$
 
 ### Example: analyzing the graphene crystal structure
 
@@ -96,75 +265,97 @@ ABCABC stacking $\rightarrow$ _cubic close packed_, also known as _face centered
 
 
 ```python
-s = np.linspace(-1, 1, 100)
-t = np.linspace(-1, 1, 100)
-tGrid, sGrid = np.meshgrid(s, t)
-
-x1 = 1 + sGrid + tGrid 
-y1 = - sGrid 
-z1 = - tGrid                  
-
-surface1 = go.Surface(x=x1, y=y1, z=z1, opacity=0.7, showscale=False)
-
-
-x2 = 1 + sGrid + tGrid 
-y2 = 1 - sGrid 
-z2 = -tGrid          
+X = np.linspace(0, 1, 100)
+Y = np.linspace(0, 1, 100)
+X, Y = np.meshgrid(X, Y)
+
+Z1 = 1 - X - Y
+surface1 = go.Surface(x=X, y=Y, z=Z1, opacity=0.7, showscale=False,cmax=1,cmin=0)
+
+Z2 = 2 - X - Y        
+surface2 = go.Surface(x=X, y=Y, z=Z2, opacity=0.7, showscale=False,cmax=1,cmin=0)
+
+
+VEC_BLACK = [
+    [0,0,0],[1,1,1]
+]
+VEC_RED = [
+    [1,0,0],[0,1,0],[0,0,1],[0.5,0.5,0],[0.5,0,0.5],[0,0.5,0.5]
+]
+VEC_BLUE = [
+    [1,1,0],[0,1,1],[1,0,1],[0.5,0.5,1],[0.5,1,0.5],[1,0.5,0.5]
+]
+
+COLORS = ['rgb(0,0,0)','rgb(33,64,154)','rgb(255,0,0)']
+
+def scatter(vec_list,color_code):
+    vec_list = np.transpose(vec_list)
+    trace=go.Scatter3d(x=vec_list[0],
+                   y=vec_list[1],
+                   z=vec_list[2],
+                   mode = 'markers',
+                   marker = dict(
+                            sizemode = 'diameter',
+                            sizeref = 20,
+                            size = 30,
+                            color = color_code
+                           )
+                         )
+    return trace
+
+x_axis = go.Scatter3d(x=[0,1],
+                   y=[0,0],
+                   z=[0,0],
+                   mode = 'lines',
+                   line_width = 10,
+                   line_color = 'Black'
+                     )
 
-surface2 = go.Surface(x=x2, y=y2, z=z2, opacity=0.7, showscale=False)
+y_axis = go.Scatter3d(x=[0,0],
+                   y=[0,1],
+                   z=[0,0],
+                   mode = 'lines',
+                   line_width = 10,
+                   line_color = 'Black'
+                     )
 
 
-Xn = np.tile(np.arange(0,2,1),4)
-Yn = np.repeat(np.arange(0,2,1),4)
-Zn = np.tile(np.repeat(np.arange(0,2,1),2),2)
+z_axis = go.Scatter3d(x=[0,0],
+                   y=[0,0],
+                   z=[0,1],
+                   mode = 'lines',
+                   line_width = 10,
+                   line_color = 'Black'
+                     )
 
-Xn = np.hstack((Xn, Xn, Xn+0.5, Xn+0.5))
-Yn = np.hstack((Yn, Yn+0.5, Yn+0.5, Yn))
-Zn = np.hstack((Zn, Zn+0.5, Zn, Zn+0.5))
+data = [scatter(i,COLORS[index]) for index,i in enumerate([VEC_BLACK,VEC_RED,VEC_BLUE])]
+data.append(surface1)
+data.append(surface2)
+data.append(x_axis)
+data.append(y_axis)
+data.append(z_axis)
+
+
+scene_axis_settings = lambda axis_name : dict(
+                        title = axis_name,
+                        range = [0,1],
+                        ticks ='',
+                        showbackground = False,
+                        showgrid = False,
+                        showline = False,
+                        showspikes = False,
+                        showticklabels = False
+                        )
 
-trace1=go.Scatter3d(x=Xn,
-               y=Yn,
-               z=Zn,
-               mode = 'markers',
-               marker = dict(
-                        sizemode = 'diameter',
-                        sizeref = 20,
-                        size = 20,
-                        color = 'rgb(255,255,255)',
-                        line = dict(
-                               color = 'rgb(0,0,0)',
-                               width = 5
-                               )
-                       )
-                     )
- 
 layout=go.Layout(showlegend = False,
-                scene = dict(
+                 scene = dict(
                         aspectmode= 'cube',
-                        xaxis=dict(
-                        title= 'x[a]',
-                        range= [0,1],
-                        ticks='',
-                        showticklabels=False
-                        ),
-                        yaxis=dict(
-                        title= 'y[a]',
-                        range= [0,1],
-                        ticks='',
-                        showticklabels=False
-                        ),
-                        zaxis=dict(
-                        title= 'z[a]',
-                        range= [0,1],
-                        ticks='',
-                        showticklabels=False
-                        )
-                    ))
-
-data=[trace1, surface1, surface2]
-
-fig=go.Figure(data=data, layout=layout)
-
+                        xaxis=scene_axis_settings('X'),
+                        yaxis=scene_axis_settings('Y'),
+                        zaxis=scene_axis_settings('Z')
+                    )
+                )
+fig=go.Figure(data=data,layout=layout)
 py.iplot(fig, filename='FCC')
 ```
 
-- 
GitLab